Bitte helfen Sie mir, den Anwendungsfall dahinter zu verstehen SELECT ... FOR UPDATE
.
Frage 1 : Ist das Folgende ein gutes Beispiel dafür, wann SELECT ... FOR UPDATE
es verwendet werden sollte?
Gegeben:
- Zimmer [id]
- Tags [ID, Name]
- room_tags [room_id, tag_id]
- room_id und tag_id sind Fremdschlüssel
Die Anwendung möchte alle Räume und ihre Tags auflisten, muss jedoch zwischen Räumen ohne Tags und Räumen unterscheiden, die entfernt wurden. Wenn SELECT ... FOR UPDATE nicht verwendet wird, kann Folgendes passieren:
- Anfänglich:
- Zimmer enthält
[id = 1]
- Tags enthält
[id = 1, name = 'cats']
- room_tags enthält
[room_id = 1, tag_id = 1]
- Zimmer enthält
- Thread 1:
SELECT id FROM rooms;
returns [id = 1]
- Thread 2:
DELETE FROM room_tags WHERE room_id = 1;
- Thread 2:
DELETE FROM rooms WHERE id = 1;
- Thread 2: [schreibt die Transaktion fest]
- Thread 1:
SELECT tags.name FROM room_tags, tags WHERE room_tags.tag_id = 1 AND tags.id = room_tags.tag_id;
- gibt eine leere Liste zurück
Jetzt denkt Thread 1, dass Raum 1 keine Tags hat, aber in Wirklichkeit wurde der Raum entfernt. Um dieses Problem zu lösen, sollte Thread 1 verwendet werden SELECT id FROM rooms FOR UPDATE
, wodurch verhindert wird, dass Thread 2 gelöscht wird, rooms
bis Thread 1 fertig ist. Ist das korrekt?
Frage 2 : Wann sollte man verwenden SERIALIZABLE
Transaktion Isolation gegenüber READ_COMMITTED
mit SELECT ... FOR UPDATE
?
Es wird erwartet, dass die Antworten portabel sind (nicht datenbankspezifisch). Wenn dies nicht möglich ist, erklären Sie bitte warum.
REPEATABLE_READ
undREAD_COMMITTED
sogar tragbare Optionen? Die einzigen Ergebnisse, die ich für diese bekomme, sind für MSSQL ServerREAD COMMITTED
Modus beispielsweise nicht definiert wird, ob tatsächlich Datensätze angezeigt werden, die von einer anderen Transaktion festgeschrieben wurden. Es wird lediglich sichergestellt, dass niemals nicht festgeschriebene Datensätze angezeigt werden.select ... for update
aufrooms
erlauben nochroom_tags
gelöscht werden , weil sie getrennte Tabellen sind. Wollten Sie fragen, ob diefor update
Klausel Löschungen verhindertrooms
?Antworten:
Die einzige tragbare Möglichkeit, die Konsistenz zwischen Räumen und Tags zu erreichen und sicherzustellen, dass Räume nach dem Löschen nie zurückgegeben werden, besteht darin, sie zu sperren
SELECT FOR UPDATE
.In einigen Systemen ist das Sperren jedoch ein Nebeneffekt der Parallelitätskontrolle, und Sie erzielen dieselben Ergebnisse, ohne dies
FOR UPDATE
explizit anzugeben .Dies hängt von der Parallelitätskontrolle ab, die Ihr Datenbanksystem verwendet.
MyISAM
inMySQL
(und mehreren anderen alten Systemen) sperrt die gesamte Tabelle für die Dauer einer Abfrage.In
SQL Server
,SELECT
Abfragen Ort eines Shared - Sperren auf den Aufzeichnungen / pages / Tabellen sie untersucht haben, währendDML
Abfragen statt Update - Sperren (die später zu gemeinsamen Sperren , um exklusiven oder degradiert befördert zu werden ). Exklusive Sperren sind nicht mit gemeinsam genutzten Sperren kompatibel. Daher wird entwederSELECT
oder dieDELETE
Abfrage gesperrt, bis eine andere Sitzung festgeschrieben wird.In Datenbanken , die Verwendung
MVCC
(wieOracle
,PostgreSQL
,MySQL
mitInnoDB
), eineDML
erstellten Abfrage eine Kopie des Datensatz (in der einen oder anderen Art und Weise) und in der Regel kehrt nicht blockieren Schriftsteller und vice Leser. Für diese DatenbankenSELECT FOR UPDATE
wäre a praktisch: Es würde entwederSELECT
oder dieDELETE
Abfrage sperren, bis eine andere Sitzung festgeschrieben wird, genau wie dies derSQL Server
Fall ist.REPEATABLE READ
Verbietet im Allgemeinen keine Phantomzeilen (Zeilen, die in einer anderen Transaktion angezeigt oder verschwunden sind, anstatt geändert zu werden)In
Oracle
und früherenPostgreSQL
VersionenREPEATABLE READ
ist eigentlich ein Synonym fürSERIALIZABLE
. Grundsätzlich bedeutet dies, dass die Transaktion nach dem Start keine Änderungen mehr sieht. In diesem Setup gibt die letzteThread 1
Abfrage den Raum zurück, als wäre er nie gelöscht worden (was möglicherweise das ist, was Sie wollten oder nicht). Wenn Sie die Räume nach dem Löschen nicht mehr anzeigen möchten, sollten Sie die Zeilen mit sperrenSELECT FOR UPDATE
In
InnoDB
,REPEATABLE READ
undSERIALIZABLE
sind verschiedene Dinge: Leser -SERIALIZABLE
Modus Set Next-Key - Sperre für die Aufzeichnungen sie bewerten, effektiv die gleichzeitige VerhinderungDML
auf sich. Sie benötigen also keinenSELECT FOR UPDATE
im serialisierbaren Modus, sondern benötigen ihn inREPEATABLE READ
oderREAD COMMITED
.Beachten Sie, dass der Standard für Isolationsmodi vorschreibt, dass Sie bestimmte Macken in Ihren Abfragen nicht sehen, aber nicht definieren, wie (mit Sperren oder mit
MVCC
oder auf andere Weise).Wenn ich "Sie brauchen nicht
SELECT FOR UPDATE
" sage, hätte ich wirklich "wegen der Nebenwirkungen bestimmter Datenbank-Engine-Implementierungen" hinzufügen sollen.quelle
SERIALIZABLE
im Vergleich zuREAD_COMMITTED
mit verwendet werden sollteSELECT ... FOR UPDATE
. Können Sie bitte Ihre Antwort aktualisieren, um diese aktualisierte Frage widerzuspiegeln?SELECT FOR UPDATE
im serialisierbaren Modus", mitInnoDB
. Bei den anderenMVCC
Systemen sind die beiden Synonyme und Sie benötigenSELECT FOR UPDATE
.This depends on the concurrency control your database system is using
: Ich denke du spaltest Haare. Alle Fälle, die Sie unten auflisten, besagen, dass der Raum zwischenSELECT
dem Ende der Transaktion nicht gelöscht wird. Sollte die Antwort nicht einfachYes
mit den folgenden unterstützenden Referenzen sein?Kurze Antworten:
Q1: Ja.
F2: Egal welche Sie verwenden.
Lange Antwort:
A
select ... for update
wird (wie impliziert) bestimmte Zeilen auswählen, sie aber auch sperren, als ob sie bereits von der aktuellen Transaktion aktualisiert worden wären (oder als ob die Identitätsaktualisierung durchgeführt worden wäre). Auf diese Weise können Sie sie in der aktuellen Transaktion erneut aktualisieren und dann festschreiben, ohne dass eine andere Transaktion diese Zeilen in irgendeiner Weise ändern kann.Eine andere Sichtweise ist, als ob die folgenden zwei Anweisungen atomar ausgeführt werden:
Da die von betroffenen Zeilen
my_condition
gesperrt sind, kann keine andere Transaktion sie in irgendeiner Weise ändern, und daher macht die Transaktionsisolationsstufe hier keinen Unterschied.Beachten Sie auch, dass die Transaktionsisolationsstufe unabhängig vom Sperren ist: Wenn Sie eine andere Isolationsstufe festlegen, können Sie das Sperren und Aktualisieren von Zeilen in einer anderen Transaktion, die von Ihrer Transaktion gesperrt werden, nicht umgehen.
Was Transaktionsisolationsstufen (auf verschiedenen Ebenen) garantieren, ist die Konsistenz der Daten während laufender Transaktionen.
quelle
What transaction isolation levels do guarantee [...] is the consistency of data once transactions are completed.
fälschlicherweise impliziert dies, dass Isolationsstufen keinen Einfluss darauf haben, was während einer Transaktion passiert . Ich empfehle, diesen Abschnitt zu überarbeiten und detailliertere Informationen darüber zu liefern, wie sie sich auf das auswirken, was Sie während einer Transaktion sehen (oder nicht sehen).