PostgreSQL
 sql >> Baza danych >  >> RDS >> PostgreSQL

org.postgresql.util.PSQLException:BŁĄD:nie można serializować dostępu z powodu zależności odczytu/zapisu między transakcjami

Za każdym razem, gdy poprosisz o SERIALIZABLE izolacja, że ​​DB będzie próbował wykonać współbieżne zestawy zapytań wydaje się, że zostały wykonane seryjnie pod względem uzyskiwanych wyników. Nie zawsze jest to możliwe, m.in. gdy dwie transakcje mają wzajemne zależności. W takim przypadku PostgreSQL przerwie jedną z transakcji z błędem niepowodzenia serializacji, mówiącym, że powinieneś spróbować ponownie.

Kod, który używa SERIALIZABLE musi być zawsze przygotowany na ponowną próbę transakcji. Musi sprawdzić SQLSTATE a w przypadku niepowodzeń serializacji powtórz transakcję.

Zobacz dokumentację dotyczącą izolacji transakcji .

W tym przypadku myślę, że Twoim głównym nieporozumieniem może być to, że:

ponieważ nie jest to nic w tym rodzaju, jest to INSERT ... SELECT dotyka vo_business.repositoryoperation do czytania i pisania. To wystarczy, aby stworzyć potencjalną zależność z inną transakcją, która robi to samo, lub taką, która odczytuje i zapisuje do tabeli w inny sposób.

Dodatkowo, serializowalny kod izolacji może w pewnych okolicznościach zdegenerować się do przechowywania informacji o zależnościach na poziomie bloku ze względu na wydajność. Więc niekoniecznie musi to być transakcja dotykająca tych samych wierszy, tylko tego samego bloku pamięci, szczególnie pod obciążeniem.

PostgreSQL woli przerwać transakcję, którą można serializować, jeśli nie jest pewien, czy jest bezpieczna. System dowodowy ma ograniczenia. Możliwe więc, że właśnie znalazłeś przypadek, który go oszuka.

Aby mieć pewność, muszę zobaczyć obie transakcje obok siebie, ale oto dowód pokazujący insert ... select może kłócić się z samym sobą. Otwórz trzy psql sesje i przebieg:

session0: CREATE TABLE serialdemo(x integer, y integer);

session0: BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE;

session0: LOCK TABLE serialdemo IN ACCESS EXCLUSIVE MODE;

session1: BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE;

session2: BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE;

session1: INSERT INTO serialdemo (x, y)
          SELECT 1, 2
          WHERE NOT EXISTS (SELECT 1 FROM serialdemo WHERE x = 1);

session2: INSERT INTO serialdemo (x, y)
          SELECT 1, 2
          WHERE NOT EXISTS (SELECT 1 FROM serialdemo WHERE x = 1);

session0: ROLLBACK;

session1: COMMIT;

session2: COMMIT;

session1 zobowiąże się dobrze. sesja2 zakończy się niepowodzeniem z:

ERROR:  could not serialize access due to read/write dependencies among transactions
DETAIL:  Reason code: Canceled on identification as a pivot, during commit attempt.
HINT:  The transaction might succeed if retried.

To nie jest ten sam błąd serializacji, co w Twoim przypadku i nie dowodzi, że Twój instrukcje mogą być ze sobą w konflikcie, ale pokazuje, że insert ... select nie jest tak atomowy, jak myślałeś.




  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. JPA 2:użycie wielu kolumn w kluczach obcych

  2. Postgresql:Nieprawidłowe wyrażenie regularne:nieprawidłowy numer wstecznej referencji

  3. znajdź podobne książki na podstawie zakupionych książek na podstawie meta słów kluczowych książki

  4. postgresql nextval pytanie o sekwencje

  5. Dodaj brakujący miesiąc w wyniku z wartościami z poprzedniego miesiąca