Chociaż sugestia Erwina jest prawdopodobnie najprostsza sposób na uzyskanie poprawnego zachowania (o ile ponawiasz transakcję, jeśli otrzymasz wyjątek z SQLSTATE
40001), aplikacje kolejkujące z natury działają lepiej z blokowaniem żądań, aby mieć szansę na zmianę w kolejce, niż z implementacją SERIALIZABLE
w PostgreSQL transakcji, co pozwala na wyższą współbieżność i jest nieco bardziej „optymistyczne” co do prawdopodobieństwa kolizji.
Przykładowe zapytanie w pytaniu, w obecnej formie, w domyślnym READ COMMITTED
poziom izolacji transakcji umożliwiłby dwóm (lub więcej) równoczesnym połączeniom zarówno „odebranie” tego samego wiersza z kolejki. Co się stanie, to:
- T1 uruchamia się i dochodzi do zablokowania wiersza w
UPDATE
faza. - T2 nakłada się na T1 w czasie wykonywania i próbuje zaktualizować ten wiersz. Blokuje oczekujące na
COMMIT
lubROLLBACK
z T1. - T1 zatwierdza, po pomyślnym „zajęciu” wiersza.
- T2 próbuje zaktualizować wiersz, stwierdza, że T1 już ma, szuka nowej wersji wiersza, stwierdza, że nadal spełnia kryteria wyboru (czyli po prostu ten
id
dopasowania), a także „zajmuje” wiersz.
Można go zmodyfikować, aby działał poprawnie (jeśli używasz wersji PostgreSQL, która umożliwia FOR UPDATE
klauzula w podzapytaniu). Po prostu dodaj FOR UPDATE
do końca podzapytania, które wybiera identyfikator, a stanie się to:
- T1 uruchamia się i blokuje teraz wiersz przed wybraniem identyfikator.
- T2 nakłada się na T1 w czasie wykonania i blokuje podczas próby wybrania identyfikatora, w oczekiwaniu na
COMMIT
lubROLLBACK
z T1. - T1 zatwierdza, po pomyślnym „zajęciu” wiersza.
- Zanim T2 będzie w stanie czytać wiersz, aby zobaczyć identyfikator, widzi, że został zgłoszony, więc znajduje następny dostępny identyfikator.
W REPEATABLE READ
lub SERIALIZABLE
na poziomie izolacji transakcji, konflikt zapisu spowodowałby błąd, który można wykryć i określić jako błąd serializacji w oparciu o stan SQLSTATE, i spróbować ponownie.
Jeśli generalnie chcesz SERIALIZOWAĆ transakcje, ale chcesz uniknąć ponownych prób w obszarze kolejkowania, możesz to osiągnąć za pomocą blokady doradczej.