Freigeben über


Einführung in die Datenparallelität in ADO.NET

Aktualisiert: November 2007

Wenn mehrere Benutzer gleichzeitig versuchen, Daten zu ändern, müssen Sicherheitsebenen eingebaut werden, um zu verhindern, dass die Änderungen eines Benutzers ungewollt mit den Änderungen anderer Benutzer in Konflikt geraten. Das in dieser Situation greifende System wird als Parallelitätssteuerung bezeichnet.

Typen der Parallelitätssteuerung

Grundsätzlich gibt es drei Möglichkeiten, um die Parallelität in einer Datenbank zu verwalten:

  • Eingeschränkte Parallelitätssteuerung: Eine Zeile ist für Benutzer von dem Zeitpunkt an, an dem der Datensatz abgerufen wird, bis zu seiner Aktualisierung in der Datenbank nicht verfügbar.

  • Vollständige Parallelitätssteuerung: Eine Zeile ist für andere Benutzer nur während der tatsächlichen Aktualisierung der Daten nicht verfügbar. Bei der Aktualisierung wird die Zeile in der Datenbank überprüft, und es wird festgestellt, ob Änderungen vorgenommen wurden. Der Versuch, einen bereits geänderten Datensatz zu aktualisieren, führt zu einer Parallelitätsverletzung.

  • "Last in wins": Ein Zeile ist für andere Benutzer nur während der tatsächlichen Aktualisierung der Daten nicht verfügbar. Es wird jedoch kein Versuch unternommen, die Aktualisierungen mit dem ursprünglichen Datensatz zu vergleichen. Der Datensatz wird einfach geschrieben, wobei Änderungen, die seit der letzten Aktualisierung der Datensätze von anderen Benutzern vorgenommen wurden, möglicherweise überschrieben werden.

Eingeschränkte Parallelität

Die eingeschränkte Parallelität wird typischerweise aus zwei Gründen verwendet. Erstens, weil in einigen Situationen ein erhöhtes Konfliktpotential für Datensätze besteht. Die Kosten, die durch das Sperren von Daten entstehen, fallen geringer aus als die Kosten, die durch das Zurücksetzen von Änderungen im Falle von Parallelitätskonflikten anfallen.

Die eingeschränkte Parallelität ist außerdem hilfreich in Situationen, in denen es sich für den Datensatz nachteilig auswirken könnte, wenn er während einer Transaktion geändert würde. Ein gutes Beispiel dafür ist eine Bestandskontrollanwendung. Stellen Sie sich in einer Firma einen zuständigen Mitarbeiter vor, der den Bestand für einen potenziellen Kunden überprüft. Normalerweise würden Sie den Datensatz sperren, bis eine Bestellung erstellt wurde. Dabei erhält der Artikel normalerweise den Status "bestellt" und wird aus dem verfügbaren Bestand entfernt. Wenn keine Bestellung eingeht, würde die Sperrung aufgehoben werden, damit andere Benutzer, die den Bestand prüfen, verlässliche Bestandszahlen erhalten.

Die eingeschränkte Parallelitätssteuerung ist in einer Architektur ohne dauerhafte Verbindungen jedoch nicht möglich. Verbindungen sind nur so lange geöffnet, wie Daten eingelesen oder aktualisiert werden. Sperren können daher nicht über einen längeren Zeitraum aufrecht erhalten werden. Darüber hinaus ist eine Anwendung, die Sperren längerfristig beibehält, nicht skalierbar.

Vollständige Parallelität

Bei der vollständigen Parallelität werden Sperren nur so lange gesetzt und aufrecht erhalten, wie auf die Datenbank zugegriffen wird. Durch Sperren werden andere Benutzer daran gehindert, Datensätze gleichzeitig zu aktualisieren. Die Daten stehen uneingeschränkt zur Verfügung, außer in dem Moment, in dem die eigentliche Aktualisierung stattfindet. Weitere Informationen finden Sie unter Vollständige Parallelität (ADO.NET).

Bei einem Aktualisierungsversuch wird die ursprüngliche Version einer geänderten Zeile mit der vorhandenen Zeile in der Datenbank verglichen. Weichen die Zeilen voneinander ab, schlägt die Aktualisierung mit einem Parallelitätsfehler fehl. In diesem Fall müssen Sie die beiden Zeilen selbst abgleichen, indem Sie eine spezielle Geschäftslogik programmieren.

Last in Wins

Bei "Last in Wins" werden die ursprünglichen Daten nicht überprüft, und die Aktualisierung wird einfach in die Datenbank geschrieben. Dabei kann sich natürlich folgendes Szenario ergeben:

  • Benutzer A ruft einen Datensatz aus der Datenbank ab.

  • Benutzer B ruft denselben Datensatz aus der Datenbank ab, ändert ihn und schreibt den aktualisierten Datensatz in die Datenbank zurück.

  • Benutzer A ändert den "alten" Datensatz und schreibt ihn in die Datenbank zurück.

Im vorangehenden Szenario hat Benutzer A die von Benutzer B vorgenommenen Änderungen nie zu Gesicht bekommen. Wenn Sie beabsichtigen, die Parallelitätssteuerung mit dem "Last in Wins"-Ansatz zu verwenden, sollten Sie sicherstellen, dass diese Voraussetzung akzeptabel für Sie ist.

Parallelitätssteuerung in ADO.NET und Visual Studio

In ADO.NET und Visual Studio wird die vollständige Parallelität verwendet, da die Datenarchitektur auf nicht dauerhaft verbundenen Daten basiert. Aus diesem Grund müssen Probleme im Zusammenhang mit der vollständigen Parallelität mithilfe einer zusätzlichen Geschäftslogik gelöst werden.

Wenn Sie sich für die vollständige Parallelität entscheiden, können Sie auf zwei Weisen feststellen, ob Änderungen vorgenommen wurden: durch Versionsprüfung (echte Versionsnummern oder Date-/Timestamps) oder durch Speichern aller Werte.

Verwenden von Versionsnummern

Bei diesem Ansatz muss der zu aktualisierende Datensatz über eine Spalte verfügen, die einen Date-/Timestamp oder eine Versionsnummer enthält. Der Date-/Timestamp oder eine Versionsnummer wird auf dem Client gespeichert, wenn der Datensatz eingelesen wird. Dieser Wert wird dadurch zu einem Teil der Aktualisierung.

Eine Möglichkeit, die Parallelität sicherzustellen, besteht darin, die Aktualisierung auf Situationen zu beschränken, in denen die WHERE-Klausel mit dem Wert im Datensatz übereinstimmt. Die SQL-Darstellung dieses Ansatzes sieht wie folgt aus:

UPDATE Table1 SET Column1 = @newvalue1, Column2 = @newvalue2 
WHERE DateTimeStamp = @origDateTimeStamp

Alternativ dazu kann der Vergleich anhand der Versionsnummer durchgeführt werden:

UPDATE Table1 SET Column1 = @newvalue1, Column2 = @newvalue2 
WHERE RowVersion = @origRowVersionValue

Wenn Date-/Timestamps oder Versionsnummern übereinstimmen, wurde der Datensatz im Datenspeicher nicht geändert und kann ohne Risiko mit den neuen Werten aus dem DataSet aktualisiert werden. Besteht keine Übereinstimmung, wird ein Fehler zurückgegeben. Sie können Code schreiben, um diese Art der Parallelitätsprüfung in Visual Studio zu implementieren. Außerdem müssen Sie Code programmieren, mit dem Sie auf Aktualisierungskonflikte reagieren können. Um den Date-/Timestamp oder die Versionsnummer aktuell zu halten, müssen Sie in der Tabelle einen Trigger vorsehen, der den Stamp oder die Nummer bei einer Zeilenänderung aktualisiert.

Speichern aller Werte

Eine Alternative zur Verwendung eines Date-/Timestamps oder einer Versionsnummer besteht darin, beim Einlesen des Datensatzes Kopien aller Felder abzurufen. Das DataSet-Objekt in ADO.NET verwaltet von jedem geänderten Datensatz zwei Versionen: Eine Originalversion (die ursprünglich aus der Datenquelle gelesen wurde) und eine geänderte Version, die die Benutzeraktualisierungen darstellt. Beim Versuch, den Datensatz in die Datenquelle zurückzuschreiben, werden die ursprünglichen Werte in der Datenzeile mit dem Datensatz in der Datenquelle verglichen. Falls sie übereinstimmen, wurde der Datensatz in der Datenbank seit dem Einlesen nicht geändert. In diesem Fall werden die geänderten Werte aus dem DataSet erfolgreich in die Datenbank geschrieben.

Jeder Datenadapterbefehl verfügt für jeden seiner vier Befehle (DELETE, INSERT, SELECT und UPDATE) über eine Parameterauflistung. Jeder Befehl verfügt sowohl für die ursprünglichen als auch für die aktuellen (oder geänderten) Werte über Parameter.

Hinweis:

Beim Hinzufügen neuer Datensätze (mit dem INSERT-Befehl) sind nur aktuelle Werte erforderlich, da kein ursprünglicher Datensatz existiert. Im Unterschied dazu sind beim Entfernen von Datensätzen (mit dem DELETE-Befehl) nur ursprüngliche Werte erforderlich, mit denen der zu löschende Datensatz gesucht wird.

Im folgenden Beispiel wird der Befehlstext für einen DataSet-Befehl angezeigt, mit dem eine typische Customers-Tabelle aktualisiert wird. Der Befehl ist für dynamisches SQL und vollständige Parallelität ausgelegt.

UPDATE Customers SET CustomerID = @currCustomerID, CompanyName = @currCompanyName, ContactName = @currContactName,
       ContactTitle = currContactTitle, Address = @currAddress, City = @currCity, 
       PostalCode = @currPostalCode, Phone = @currPhone, Fax = @currFax
WHERE (CustomerID = @origCustomerID) AND (Address = @origAddress OR @origAddress IS NULL AND Address IS NULL) AND (City = @origCity OR @origCity IS NULL AND City IS NULL)
      AND (CompanyName = @origCompanyName OR @origCompanyName IS NULL AND CompanyName IS NULL) AND (ContactName = @origContactName OR @origContactName IS NULL AND ContactName IS NULL) AND (ContactTitle = @origContactTitle OR @origContactTitle IS NULL AND ContactTitle IS NULL) 
      AND (Fax = @origFax OR @origFax IS NULL AND Fax IS NULL) AND (Phone = @origPhone OR @origPhone IS NULL AND Phone IS NULL) AND (PostalCode = @origPostalCode OR @origPostalCode IS NULL AND PostalCode IS NULL);
SELECT CustomerID, CompanyName, ContactName, ContactTitle, Address, City,
       PostalCode, Phone, Fax
FROM Customers WHERE (CustomerID = @currCustomerID)

Beachten Sie, dass die neun Parameter der SET-Anweisung die aktuellen Werte darstellen, die in die Datenbank geschrieben werden. Demgegenüber stellen die neun Parameter der WHERE-Anweisung die ursprünglichen Werte dar, die zur Suche des ursprünglichen Datensatzes verwendet werden.

Die ersten neun Parameter in der SET-Anweisung entsprechen den ersten neun Parametern in der Parameterauflistung. Die SourceVersion-Eigenschaft dieser Parameter ist auf Current festgelegt.

Die nächsten neun Parameter in der WHERE-Anweisung werden für die vollständige Parallelität verwendet. Diese Platzhalter entsprechen den nächsten neun Parametern in der Parameterauflistung, und die SourceVersion-Eigenschaft jeder dieser Parameter ist auf Original festgelegt.

Die SELECT-Anweisung wird nach erfolgter Übernahme der Daten zur Aktualisierung des DataSets verwendet. Diese Anweisung wird erstellt, wenn Sie im Dialogfeld Erweiterte SQL-Generierungsoptionen die Option DataSet aktualisieren festlegen.

Hinweis:

In der oben erwähnten SQL-Anweisung werden benannte Parameter verwendet, während in OleDbDataAdapter-Befehlen Fragezeichen (?) als Parameterplatzhalter verwendet werden.

Diese Parameter werden standardmäßig von Visual Studio erstellt, wenn im Datenadapter-Konfigurations-Assistent die Option Vollständige Parallelität ausgewählt wird. Je nach Ihren Unternehmensanforderungen können Sie in eigenem Ermessen Fehlerbehandlungscode hinzufügen. ADO.NET bietet ein DBConcurrencyException-Objekt, das die Zeile zurückgibt, die gegen die Parallelitätsregeln verstößt. Weitere Informationen finden Sie unter Gewusst wie: Behandeln von Parallelitätsfehlern.

Siehe auch

Aufgaben

Gewusst wie: Behandeln von Parallelitätsfehlern

Konzepte

Vollständige Parallelität (ADO.NET)

Referenz

DBConcurrencyException