PostgreSQL
 sql >> Datenbank >  >> RDS >> PostgreSQL

org.postgresql.util.PSQLException:FEHLER:Der Zugriff konnte aufgrund von Lese-/Schreibabhängigkeiten zwischen Transaktionen nicht serialisiert werden

Wann immer Sie SERIALIZABLE anfordern Isolation versucht die DB, gleichzeitige Sätze von Abfragen so erscheinen zu lassen, als wären sie seriell ausgeführt worden in Bezug auf die Ergebnisse, die sie produzieren. Dies ist nicht immer möglich, z. wenn zwei Transaktionen gegenseitige Abhängigkeiten haben. In diesem Fall wird PostgreSQL eine der Transaktionen abbrechen mit einem Serialisierungsfehler, der Ihnen mitteilt, dass Sie es erneut versuchen sollten.

Code, der SERIALIZABLE verwendet müssen immer bereit sein, Transaktionen erneut zu versuchen. Es muss den SQLSTATE überprüfen und bei Serialisierungsfehlern die Transaktion wiederholen.

Siehe Dokumentation zur Transaktionsisolierung .

In diesem Fall könnte Ihr größter Irrtum folgender sein:

da es nichts dergleichen ist, ist es ein INSERT ... SELECT die vo_business.repositoryoperation berührt sowohl zum Lesen als auch zum Schreiben. Das reicht völlig aus, um eine potenzielle Abhängigkeit mit einer anderen Transaktion zu schaffen, die dasselbe tut, oder mit einer, die auf andere Weise in die Tabelle liest und schreibt.

Außerdem kann der serialisierbare Isolationscode unter bestimmten Umständen aus Effizienzgründen dahingehend degenerieren, Abhängigkeitsinformationen auf Blockebene zu halten. Es muss also nicht unbedingt eine Transaktion sein, die dieselben Zeilen berührt, sondern nur denselben Speicherblock, insbesondere unter Last.

PostgreSQL wird es vorziehen, eine serialisierbare Transaktion abzubrechen, wenn es sich nicht sicher ist, ob sie sicher ist. Das Beweissystem hat Einschränkungen. Es ist also auch möglich, dass Sie gerade einen Fall gefunden haben, der ihn täuscht.

Um sicher zu sein, müsste ich beide Transaktionen nebeneinander sehen, aber hier ist ein Beweis, der einen insert ... select zeigt kann mit sich selbst in Konflikt geraten. Öffnen Sie drei psql Sitzungen und ausführen:

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 wird gut festgeschrieben. session2 schlägt fehl mit:

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.

Es ist nicht derselbe Serialisierungsfehler wie in Ihrem Fall und beweist nicht, dass Ihre Anweisungen können miteinander in Konflikt geraten, aber es zeigt, dass ein insert ... select ist nicht so atomar wie Sie dachten.