Die einzige portable Möglichkeit, Konsistenz zwischen Räumen und Tags zu erreichen und sicherzustellen, dass Räume nach dem Löschen nie wieder zurückgegeben werden, besteht darin, sie mit SELECT FOR UPDATE
zu sperren .
In einigen Systemen ist das Sperren jedoch ein Nebeneffekt der Parallelitätssteuerung, und Sie erzielen die gleichen Ergebnisse, ohne FOR UPDATE
anzugeben explizit.
Um dieses Problem zu lösen, sollte Thread 1 SELECT id FROM rooms FOR UPDATE
, wodurch verhindert wird, dass Thread 2 aus rooms
gelöscht wird bis Thread 1 fertig ist. Ist das richtig?
Dies hängt von der Parallelitätssteuerung ab, die Ihr Datenbanksystem verwendet.
-
MyISAM
inMySQL
(und mehrere andere alte Systeme) sperrt die gesamte Tabelle für die Dauer einer Abfrage. -
In
SQL Server
,SELECT
Abfragen setzen gemeinsame Sperren auf die Datensätze / Seiten / Tabellen, die sie untersucht haben, währendDML
Abfragen platzieren Aktualisierungssperren (die später zu exklusiven Sperren hochgestuft oder zu gemeinsam genutzten Sperren herabgestuft werden). Exklusive Sperren sind mit geteilten Sperren nicht kompatibel, also entwederSELECT
oderDELETE
Die Abfrage wird gesperrt, bis eine andere Sitzung festgeschrieben wird. -
In Datenbanken, die
MVCC
verwenden (wieOracle
,PostgreSQL
,MySQL
mitInnoDB
), eineDML
query erstellt (auf die eine oder andere Weise) eine Kopie des Datensatzes, und im Allgemeinen blockieren Leser keine Schreiber und umgekehrt. Für diese Datenbanken einSELECT FOR UPDATE
wäre praktisch:es würde entwederSELECT
sperren oder dasDELETE
Abfrage, bis eine andere Sitzung festgeschrieben wird, genau wieSQL Server
tut.
Wann sollte man REPEATABLE_READ
verwenden Transaktionsisolation gegenüber READ_COMMITTED
mit SELECT ... FOR UPDATE
?
Im Allgemeinen REPEATABLE READ
verbietet keine Phantomzeilen (Zeilen, die in einer anderen Transaktion erschienen oder verschwunden sind, anstatt geändert zu werden)
-
In
Oracle
und früherPostgreSQL
Versionen,REPEATABLE READ
ist eigentlich ein Synonym fürSERIALIZABLE
. Grundsätzlich bedeutet dies, dass die Transaktion nach dem Start keine Änderungen sieht. Also in diesem Setup der letzteThread 1
Die Abfrage gibt den Raum so zurück, als ob er nie gelöscht worden wäre (was Sie vielleicht wollten oder auch nicht). Wenn Sie die Räume nach dem Löschen nicht mehr anzeigen möchten, sollten Sie die Zeilen mitSELECT FOR UPDATE
sperren -
In
InnoDB
,REPEATABLE READ
undSERIALIZABLE
sind verschiedene Dinge:Leser inSERIALIZABLE
mode legen Next-Key-Sperren für die Datensätze fest, die sie auswerten, wodurch die gleichzeitigeDML
effektiv verhindert wird auf sie. Sie brauchen also keinSELECT FOR UPDATE
im serialisierbaren Modus, benötigen sie aber inREPEATABLE READ
oderREAD COMMITED
.
Beachten Sie, dass der Standard zu Isolationsmodi vorschreibt, dass Sie bestimmte Macken in Ihren Abfragen nicht sehen, aber nicht definiert, wie (mit Sperren oder mit MVCC
). oder anderweitig).
Wenn ich sage "Du brauchst SELECT FOR UPDATE
nicht " Ich hätte wirklich "aufgrund von Nebeneffekten bestimmter Datenbank-Engine-Implementierungen" hinzufügen sollen.