Ich habe eine Tabelle namens tblOrderNumber, die 1 Zeile und 1 Spalte hat. In dieser Tabelle wird die nächste Bestellnummer für meine E-Commerce-Website gespeichert. Es ist ABSOLUT VITAL, dass dieselbe Bestellnummer nicht mehr als einmal verwendet wird. Derzeit verwendet das Team diese gespeicherte Prozedur und es scheint gut zu funktionieren:
Meine Frage ist, garantiert UPDLOCK dies? Ich hätte gedacht, dass auch für SELECT eine Lesesperre erforderlich ist (in dem unwahrscheinlichen Fall, dass 2 Bestellungen innerhalb einer Millisekunde voneinander platziert werden und die erste das UPDATE nicht durchgeführt hat, bevor die zweite, wie ich verstehe, eine SELECT durchgeführt hat In diesem Verfahren gibt es keine Lesesperre.
DECLARE @NextOrderNumber INT
BEGIN TRANSACTION
SELECT @NextOrderNumber = NextOrderNumber
FROM tblOrderNumber (UPDLOCK)
UPDATE tblOrderNumber
SET NextOrderNumber = NextOrderNumber + 1
COMMIT
SELECT @NextOrderNumber
--Kundenimplementierung (Wäre UPDLOCK ODER SERIALIZABLE hier besser, da ich nicht denke, dass wir die vollständige Tabelle sperren müssen?)
UPDATE dbo.tblOrderNumber WITH (SERIALIZABLE) SET @NextOrderNumber = NextOrderNumber, NextOrderNumber = NextOrderNumber + 1; WHERE CustomerId=@CustomerId
Ich verwende SQL Server 2014, werde aber bald zu SQL Azure wechseln.
quelle
Antworten:
Kurze Antwort
Die Update-Sperre ist ausreichend, aber Sie können einfacher erreichen, was Sie wollen:
Der
WITH (SERIALIZABLE)
Hinweis ist nicht unbedingt erforderlich, wenn für die Kunden-ID ein eindeutiger Index vorhanden ist.Längere Antwort
Der Hinweis zur Aktualisierungssperre ist im angegebenen Code ausreichend. Es kann jeweils nur eine Transaktion eine Aktualisierungssperre (U) für eine Ressource erhalten, und Aktualisierungssperren werden bis zum Ende der Transaktion gehalten. Die Aktualisierungssperre wird unmittelbar vor der Änderung in eine exklusive (X) Sperre konvertiert. Die exklusive Sperre bleibt auch bis zum Ende der Transaktion erhalten.
Wenn Sie beim Lesen eine Aktualisierungssperre verwenden , erhalten Sie die von Ihnen gesuchten Parallelitätsgarantien. Um es klar auszudrücken: Sobald die Aktualisierungssperre (durch Auswahl) erworben wurde, kann keine andere Transaktion eine Aktualisierungssperre für dieselbe Ressource erwerben, bis die erste Transaktion festgeschrieben oder abgebrochen wurde.
Sie können die Transaktion (oder einzelne Aktualisierungsanweisung) auch ohne Hinweise auf der
SERIALIZABLE
Isolationsstufe ausführen . Schließlich ist die Garantie, die Sie suchen, dass die Transaktion nach einem serialisierbaren Zeitplan ausgeführt wird. Wenn Sie sich nicht auf das Wissen über das Sperren von Interna verlassen können, ist es wahrscheinlich einfacher, die gewünschte Isolationsstufe anzugeben und SQL Server die Details zu überlassen.Natürlich benötigen Sie Code, um auch Fehler oder mögliche Deadlocks zu behandeln. Ich gehe davon aus, dass Sie dies in Ihrem Beispiel weggelassen haben. Ein Belt-and-Braces-Ansatz würde auch
SET XACT_ABORT ON
für das Verfahren sicherstellen, dass fast alle möglichen Fehler die Transaktion abbrechen, anstatt stillschweigend fortzufahren.Es wäre auch möglich, eine robuste Sperrimplementierung manuell mithilfe von Anwendungssperren (mit
sp_getapplock
undsp_releaseapplock
) zu schreiben , aber ehrlich gesagt ist die Verwendung der integrierten serialisierbaren Isolationsstufe wahrscheinlich am einfachsten.Weitere Informationen finden Sie in meiner Artikelserie:
quelle