Optimistisches Sperren

Eintrag zuletzt aktualisiert am: 07.04.2017

Optimistisches Sperren ist ein Verfahren, mit dem Datenzugriffstechniken feststellen, ob ein Datensatz mittlerweile von einem anderen Prozess geändert wurde.

Optimistisches Sperren ist ein Euphemismus, denn tatsächlich wird dabei im Datenbankmanagementsystem und im RAM nichts gesperrt. Es wird lediglich dafür gesorgt, dass Änderungskonflikte nachträglich auffallen. Der erste Prozess, der eine Änderung schreiben will, gewinnt. Und alle weiteren Prozesse können nicht schreiben und bekommen eine Fehlermeldung. Um dies zu erreichen werden bei UPDATE- und DELETE-Befehlen in die WHERE-Bedingung einzelne oder mehrere Werte aus dem Ursprungsdatensatz aufgenommen.

Anwendungen des Optimistisches Sperren in .NET

  • Command Builder für das DataSet in ADO.NET
  • Entity Framework: ConcurrencyCheckAttribute auf Entitätsklassenproperties bzw. Eigenschaft Concurreny Mode = Fixed im EDMX-Designer

Beispiel

Das DataSet in Verbindung mit dem DataAdapter und einem CommandBuilder-Objekt fragt dazu in der WHERE-Bedingung eines UPDATE- oder DELETE-Befehls nicht nur den oder die Primärschlüsselspalten ab, sondern alle Spalten mit ihrem alten Wert aus der Sicht des aktuellen Prozesses, also den Werten, die der Prozess beim Lesen des Datensatzes erhalten hat (siehe Listing 1). Wenn zwischenzeitlich ein anderer Prozess einzelne Spalten geändert hat, führt der UPDATE- oder DELETE-Befehl zwar nicht zu einem Laufzeitfehler im Datenbankmanagementsystem, aber zum Ergebnis, dass „0“ Datensätze betroffen waren. Daran kann der Datenadapter erkennen, dass es einen Änderungskonflikt gab.

UPDATE [dbo].[Flug]
SET [FlugNr] = @p1, [Abflugort] = @p2, [Bestreikt] = @p3, [CopilotId] = @p4, [FlugDatum] = @p5, [Fluggesellschaft] = @p6, [FlugzeugTypID] = @p7, [FreiePlaetze] = @p8, [LetzteAenderung] = @p9, [Memo] = @p10, [NichtRaucherFlug] = @p11, [PilotId] = @p12, [Plaetze] = @p13, [Preis] = @p14, [Timestamp] = @p15, [Zielort] = @p16
WHERE (([FlugNr] = @p17) AND ((@p18 = 1 AND [Abflugort] IS NULL) OR ([Abflugort] = @p19)) AND ((@p20 = 1 AND [Bestreikt] IS NULL) OR ([Bestreikt] = @p21)) AND ((@p22 = 1 AND [CopilotId] IS NULL) OR ([CopilotId] = @p23)) AND ([FlugDatum] = @p24) AND ([Fluggesellschaft] = @p25) AND ((@p26 = 1 AND [FlugzeugTypID] IS NULL) OR ([FlugzeugTypID] = @p27)) AND ((@p28 = 1 AND [FreiePlaetze] IS NULL) OR ([FreiePlaetze] = @p29)) AND ([LetzteAenderung] = @p30) AND ((@p31 = 1 AND [NichtRaucherFlug] IS NULL) OR ([NichtRaucherFlug] = @p32)) AND ([PilotId] = @p33) AND ([Plaetze] = @p34) AND ((@p35 = 1 AND [Preis] IS NULL) OR ([Preis] = @p36)) AND ((@p37 = 1 AND [Zielort] IS NULL) OR ([Zielort] = @p38)))
Listing 1: Update-Befehl, wie ihn ein SqlCommandBuilder für die Tabelle "Flug" mit dem Primärschlüssel "FlugNr" erzeugt.