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

Offensichtliche Verletzung der Transaktionsisolation in postgresql

Ja und Nein – wie immer kommt es darauf an. Die Dokumentation sagt streng, dass:

Mit anderen Worten, SELECT unterscheidet sich einfach von SELECT FOR UPDATE/DELETE/UPDATE.

Sie können einen einfachen Testfall erstellen, um dieses Verhalten zu beobachten:

Sitzung 1

test=> START TRANSACTION;
START TRANSACTION
test=> SELECT * FROM test;
 x
----
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
(10 rows)


test=> DELETE FROM test;
DELETE 10
test=>

Jetzt in einer anderen Sitzung anmelden 2:

test=> START TRANSACTION;
START TRANSACTION
test=> SELECT * FROM test;
 x
----
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
(10 rows)


test=> SELECT * FROM test WHERE x = 5 FOR UPDATE;

Nach dem letzten Befehl SELECT ... FOR UPDATE Sitzung 1 "hängt" und wartet auf etwas ......

Zurück in Sitzung 1

test=> insert into test select * from generate_series(1,10);
INSERT 0 10
test=> commit;
COMMIT

Und jetzt, wenn Sie zu Sitzung 2 zurückkehren, sehen Sie Folgendes:

test=> SELECT * FROM test WHERE x = 5 FOR UPDATE;
 x
---
(0 rows)


test=> select * from test;
 x
----
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
(10 rows)

Das heißt - einfach SELECT sieht immer noch keine Änderungen, während SELECT ... FOR UPDATE sieht, dass Zeilen gelöscht wurden. Aber es sieht keine neuen Zeilen, die von Sitzung 1 eingefügt wurden

Tatsächlich ist eine Sequenz, die Sie sehen, folgende:

  • Prozess A startet seine Transaktion
  • Prozess A löscht alles aus Tabelle T
  • Prozess B startet seine Transaktion
  • Prozess B versucht eine Auswahl zur Aktualisierung einer Zeile in Tabelle T
  • Prozess B "hängt" und wartet, bis Sitzung A einen Commit oder Rollback durchführt
  • Prozess A füllt Tabelle T mit eingehenden Daten neu
  • Prozess A schreibt seine Transaktion fest
  • Prozess B ist leer (0 Zeilen - nach dem Festschreiben von Sitzung A) und ruft Rollback auf