Angenommen, Sie haben den folgenden Code (bitte ignorieren Sie, dass er schrecklich ist):
BEGIN TRAN;
DECLARE @id int
SELECT @id = id + 1 FROM TableA;
UPDATE TableA SET id = @id; --TableA must have only one row, apparently!
COMMIT TRAN;
-- @id is returned to the client or used somewhere else
Meines Erachtens verwaltet dies die Parallelität NICHT ordnungsgemäß. Nur weil Sie eine Transaktion haben, heißt das nicht, dass jemand anderes nicht den gleichen Wert wie vor der Update-Anweisung liest.
Lassen Sie nun den Code unverändert (ich weiß, dass dies besser als einzelne Anweisung oder noch besser als automatische Inkrementierung / Identitätsspalte gehandhabt wird). Auf welche Weise können Sie sicherstellen, dass der gemeinsame Zugriff ordnungsgemäß verarbeitet wird, und verhindern, dass zwei Clients dieselben Bedingungen erfüllen ID-Wert?
Ich bin mir ziemlich sicher, dass das Hinzufügen von a WITH (UPDLOCK, HOLDLOCK)
zum SELECT den Trick macht. Die SERIALIZABLE-Transaktionsisolationsstufe scheint ebenfalls zu funktionieren, da sie es jedem anderen verweigert, zu lesen, was Sie getan haben, bis die Übertragung beendet ist ( UPDATE : Dies ist falsch. Siehe Martins Antwort). Ist das wahr? Funktionieren beide gleich gut? Wird einer dem anderen vorgezogen?
Stellen Sie sich vor, Sie tun etwas Berechtigteres als ein ID-Update - einige Berechnungen basieren auf einem Lesevorgang, den Sie aktualisieren müssen. Es kann viele Tabellen geben, an die Sie schreiben und an die Sie nicht schreiben. Was ist hier die beste Praxis?
Nachdem Sie diese Frage geschrieben haben, sind die Sperrhinweise meines Erachtens besser, da Sie dann nur die Tabellen sperren, die Sie benötigen, aber ich würde mich über jede Eingabe freuen.
PS Und nein, ich kenne die beste Antwort nicht und möchte wirklich ein besseres Verständnis bekommen! :)
update
, der möglicherweise auf veralteten Daten basiert? In letzteremrowversion
Fall können Sie mithilfe der Spalte überprüfen, ob die zu aktualisierende Zeile seit dem Lesen nicht mehr geändert wurde.