Opisane zachowanie jest normalne i oczekiwane w każdej transakcyjnej relacyjnej bazie danych.
Jeśli PostgreSQL pokazał ci wartość edited
dla pierwszego SELECT
byłoby to niewłaściwe – nazywa się to „brudnym odczytem” i jest złą wiadomością w bazach danych.
PostgreSQL będzie mógł czekać przy SELECT
do czasu zatwierdzenia lub wycofania, ale nie jest to wymagane przez standard SQL, nie powiedziałeś, że chcesz czekać i nie musi czekać z żadnego powodu technicznego, więc zwraca dane, o które prosiłeś do natychmiastowego. W końcu, dopóki nie zostanie zatwierdzony, ta update
istnieje tylko pewien rodzaj - nadal może się zdarzyć lub nie.
Jeśli PostgreSQL zawsze tu czekał, to szybko znalazłbyś się w sytuacji, w której tylko jedno połączenie może robić cokolwiek z bazą danych na raz. Niezbyt dobre dla wydajności i przez większość czasu całkowicie niepotrzebne.
Jeśli chcesz poczekać na jednoczesną UPDATE
(lub DELETE
), użyjesz SELECT ... FOR SHARE
. (Ale pamiętaj, że to nie zadziała w przypadku INSERT
).
Szczegóły:
SELECT
bez FOR UPDATE
lub FOR SHARE
klauzula nie przyjmuje żadnych blokad na poziomie wiersza. Tak więc widzi to, co jest bieżącym zatwierdzonym wierszem i nie ma na niego wpływu żadne transakcje w locie, które mogą modyfikować ten wiersz. Koncepcje są wyjaśnione w sekcji MVCC dokumentacji
. Ogólna idea jest taka, że PostgreSQL działa w trybie kopiowania przy zapisie, z wersjonowaniem, które pozwala mu zwrócić poprawną kopię na podstawie tego, co transakcja lub instrukcja mogła „widzieć” w momencie jej uruchomienia – co PostgreSQL nazywa „migawką”.
W domyślnym READ COMMITTED
migawki izolacji są wykonywane na poziomie instrukcji, więc jeśli SELECT
wiersz, COMMIT
zmiana w nim z innej transakcji i SELECT
ponownie zobaczysz różne wartości nawet w ramach jednej transakcji. Możesz użyć SNAPSHOT
izolacja, jeśli nie chcesz widzieć zmian zatwierdzonych po rozpoczęciu transakcji, lub SERIALIZABLE
izolacja, aby dodać dalszą ochronę przed pewnymi rodzajami wzajemnych zależności transakcji.
Zobacz rozdział dotyczący izolacji transakcji w dokumentacji .
Jeśli chcesz SELECT
aby czekać na zatwierdzenie lub wycofanie zmian w wybranych wierszach na transakcje w toku, należy użyć SELECT ... FOR SHARE
. To zablokuje blokadę pobraną przez UPDATE
lub DELETE
dopóki transakcja, która spowodowała blokadę, nie zostanie wycofana lub zatwierdzona.
INSERT
jest jednak inny - krotki po prostu nie istnieją dla innych transakcji do czasu zatwierdzenia. Jedyny sposób oczekiwania na równoczesne INSERT
s to wziąć EXCLUSIVE
blokada na poziomie tabeli, dzięki czemu wiesz, że nikt inny nie zmienia tabeli podczas jej czytania. Zwykle taka potrzeba oznacza jednak, że masz problem z projektowaniem aplikacji — Twoja aplikacja nie powinna się przejmować jeśli istnieją niezatwierdzone insert
nadal w locie.
Zobacz rozdział dotyczący jawnego blokowania w dokumentacji .