MySQL
SELECT ... FOR UPDATE mit UPDATE
Mit Transaktionen mit InnoDB (auto-commit ausgeschaltet), ein SELECT ... FOR UPDATE
ermöglichen eine Sitzung vorübergehend einen bestimmten Datensatz nach unten zu sperren (oder Datensätze), so dass keine andere Sitzung aktualisieren es.Innerhalb derselben Transaktion kann die Sitzung dann einen UPDATE
für denselben Datensatz ausführen und die Transaktion festschreiben oder zurücksetzen. Auf diese Weise können Sie den Datensatz sperren, sodass keine andere Sitzung ihn aktualisieren kann, während Sie möglicherweise eine andere Geschäftslogik ausführen.
Dies wird durch Sperren erreicht. InnoDB verwendet Indizes zum Sperren von Datensätzen, daher ist das Sperren eines vorhandenen Datensatzes einfach - sperren Sie einfach den Index für diesen Datensatz.
SELECT ... FOR UPDATE mit INSERT
, jedoch SELECT ... FOR UPDATE
mit INSERT
zu verwenden, wie sperren Sie einen Index für einen Datensatz, der noch nicht existiert? Wenn Sie die Standardisolationsstufe REPEATABLE READ
verwenden, verwendet InnoDB auch die Lücke Sperren. Solange Sie die id
(oder sogar den Bereich der IDs) zu sperren wissen, kann InnoDB die Lücke sperren, so dass kein anderer Datensatz in diese Lücke eingefügt werden kann, bis wir damit fertig sind.
Wenn Ihre id
Spalte waren eine Autoinkrement-Spalte, dann SELECT ... FOR UPDATE
mit INSERT INTO
wäre problematisch, weil Sie nicht wissen, was die neue id
war, bis Sie es eingefügt. Da Sie jedoch die id
kennen, die Sie einfügen möchten, wird mit INSERT
funktionieren.
CAVEAT
Auf der Standardisolationsstufe, SELECT ... FOR UPDATE
auf einem nicht vorhandenen Datensatz tut nicht Block andere Transaktionen. Wenn also zwei Transaktionen eine für denselben nicht vorhandenen Indexdatensatz ausführen, erhalten beide die Sperre und keiner der Transaktionen kann den Datensatz aktualisieren. Wenn beide versuchen, wird ein Deadlock erkannt, und einer wird zurückgesetzt.
Deshalb, wenn Sie nicht mit einem Deadlock beschäftigen möchten, könnten Sie tun nur die folgenden:
INSERT INTO ...
Starten Sie eine Transaktion, und führen Sie die INSERT
. Machen Sie Ihre Geschäftslogik und binden Sie die Transaktion entweder ein oder führen Sie einen Rollback durch. Sobald Sie den INSERT
auf dem nicht existenten Datensatzindex für die erste Transaktion ausführen, blockieren alle anderen Transaktionen, wenn sie versuchen, einen Datensatz mit demselben eindeutigen Index zu . Wenn die zweite Transaktion versucht, einen Datensatz mit demselben Index einzufügen, nachdem die erste Transaktion die Einfügung festschreibt, wird ein Fehler "doppelter Schlüssel" angezeigt. Behandeln Sie entsprechend.
SELECT ... LOCK IN SHARE MODE
Wenn Sie mit LOCK IN SHARE MODE
vor den INSERT
wählen, wenn eine vorherige Transaktion, dass Datensatz eingefügt hat, aber noch nicht verpflichtet, bis zur vorherige Transaktion der SELECT ... LOCK IN SHARE MODE
blockieren hat vervollständigt.
Also die Chance auf doppelten Schlüsselfehler zu reduzieren, vor allem wenn man die Schleusen für eine Weile während der Durchführung der Geschäftslogik halten, bevor sie begehen oder sie wieder rollen:
SELECT bar FROM FooBar WHERE foo = ? LOCK FOR UPDATE
- Wenn keine Datensätze zurückgegeben, dann
INSERT INTO FooBar (foo, bar) VALUES (?, ?)
Does MSSQL auch diese Syntax unterstützen? –
Es hat "mit updlock", was ich glaube, ist ziemlich das Gleiche. –