Das von Ihnen beschriebene Verhalten ist normal und wird in jeder transaktionalen relationalen Datenbank erwartet.
Wenn PostgreSQL Ihnen den Wert edited
anzeigt für das erste SELECT
es wäre falsch, dies zu tun - das nennt man "Dirty Read" und ist eine schlechte Nachricht in Datenbanken.
PostgreSQL würde beim SELECT
warten dürfen bis Sie einen Commit oder Rollback durchgeführt haben, der SQL-Standard dies jedoch nicht erfordert, Sie ihm nicht mitgeteilt haben, dass Sie warten möchten, und es aus technischen Gründen nicht warten muss, sodass die angeforderten Daten zurückgegeben werden für sofort. Immerhin, bis es festgeschrieben ist, update
existiert nur irgendwie - es könnte immer noch passieren oder auch nicht.
Wenn PostgreSQL hier immer warten würde, würden Sie schnell in eine Situation geraten, in der nur eine Verbindung gleichzeitig etwas mit der Datenbank tun könnte. Nicht schön für die Leistung und die meiste Zeit völlig unnötig.
Wenn Sie auf ein gleichzeitiges UPDATE
warten möchten (oder DELETE
), würden Sie SELECT ... FOR SHARE
verwenden . (Beachten Sie jedoch, dass dies für INSERT
nicht funktioniert ).
Einzelheiten:
SELECT
ohne FOR UPDATE
oder FOR SHARE
-Klausel nimmt keine Sperren auf Zeilenebene. Es sieht also, was auch immer die aktuell festgeschriebene Zeile ist, und wird nicht von In-Flight-Transaktionen beeinflusst, die diese Zeile möglicherweise ändern. Die Konzepte werden im MVCC-Abschnitt der Dokumentation
erklärt . Die allgemeine Idee ist, dass PostgreSQL Copy-on-Write ist, mit einer Versionierung, die es ermöglicht, die richtige Kopie zurückzugeben, basierend darauf, was die Transaktion oder Anweisung zum Zeitpunkt ihres Starts "sehen" konnte - was PostgreSQL einen "Snapshot" nennt.
In der Voreinstellung READ COMMITTED
Isolations-Snapshots werden auf Anweisungsebene erstellt, wenn Sie also SELECT
eine Reihe, COMMIT
eine Änderung von einer anderen Transaktion und SELECT
Auch hier sehen Sie unterschiedliche Werte sogar innerhalb einer Transaktion. Sie können SNAPSHOT
verwenden isolation, wenn Sie nicht möchten, dass Änderungen festgeschrieben werden, nachdem die Transaktion begonnen hat, oder SERIALIZABLE
Isolierung, um weiteren Schutz gegen bestimmte Arten von Transaktionsabhängigkeiten hinzuzufügen.
Siehe das Kapitel zur Transaktionsisolierung in der Dokumentation .
Wenn Sie ein SELECT
möchten Um auf laufende Transaktionen zu warten, um Änderungen an ausgewählten Zeilen festzuschreiben oder rückgängig zu machen, müssen Sie SELECT ... FOR SHARE
verwenden . Dadurch wird die von einem UPDATE
übernommene Sperre blockiert oder DELETE
bis die Transaktion, die die Sperre übernommen hat, rückgängig gemacht oder festgeschrieben wird.
INSERT
ist jedoch anders - die Tupel existieren einfach nicht für andere Transaktionen, bis sie festgeschrieben werden. Die einzige Möglichkeit, auf gleichzeitiges INSERT
zu warten s ist ein EXCLUSIVE
zu nehmen Sperre auf Tabellenebene, damit Sie wissen, dass niemand sonst die Tabelle ändert, während Sie sie lesen. Normalerweise bedeutet dies jedoch, dass Sie ein Designproblem in der Anwendung haben - Ihre App sollte sich nicht darum kümmern wenn es nicht festgeschriebene insert
gibt ist noch im Flug.
Siehe das Kapitel zum expliziten Sperren der Dokumentation .