Es gibt zwei allgemeine Ansätze zum Sperren.
Erstens haben Sie eine pessimistische Sperre. Bei diesem Ansatz sperren Sie die Zeile (SELECT ... FOR UPDATE
), wodurch verhindert wird, dass jemand anderes die Zeile ändert. Dann machst du das UPDATE
. Wenn Sie Ihre Änderung festschreiben, wird die Sperre aufgehoben. In diesem Fall ist keine Versionsnummer/Zeitstempel-Spalte erforderlich (zumindest um das Sperren nicht zu unterstützen) und der Code ist relativ einfach.
Der Nachteil pessimistischer Sperren ist, dass Sie die Sperre die ganze Zeit über halten müssen, während ein Benutzer auf einer Seite sitzt und möglicherweise Daten bearbeitet. Dies ist technisch sehr schwierig, wenn Sie eine webbasierte Anwendung erstellen, da HTTP ein zustandsloses Protokoll ist. Die Anforderung, die die Seite ursprünglich rendert, würde normalerweise eine Verbindung aus dem Verbindungspool erhalten, führen Sie SELECT
aus , und geben Sie die Verbindung dann an den Pool zurück, sobald die Seite fertig ist. Die nachfolgende Anforderung zum Aktualisieren der Daten würde im Allgemeinen über eine andere Verbindung mit einer anderen Datenbanksitzung erfolgen, sodass Sie die Zeile nicht in der ersten Sitzung sperren und in der zweiten aktualisieren können. Wenn Sie die Zeile pessimistisch sperren wollten, müssten Sie viel Arbeit am Backend leisten, um sicherzustellen, dass die eine Datenbankverbindung an eine bestimmte Sitzung der mittleren Ebene gebunden ist, bis der Benutzer die Bearbeitung der Daten abgeschlossen hat. Dies hat im Allgemeinen sehr negative Auswirkungen auf die Skalierbarkeit und führt zu allen möglichen Sitzungsverwaltungsproblemen – woher wissen Sie beispielsweise, ob ich eine Seite angefordert, eine Zeile gesperrt und dann meinen Browser geschlossen habe, ohne mich jemals abzumelden oder eine Änderung vorzunehmen? Wie lange werden Sie den Datensatz in der Datenbank gesperrt lassen? Was passiert, wenn eine andere Sitzung versucht, die Zeile zu sperren? Wie lange werden Sie diesen Sitzungsblock auf eine Sperre warten lassen, wenn die erste Person zum Mittagessen ausgegangen ist? Im Allgemeinen implementieren die Leute keine pessimistische Sperre in webbasierten Apps, weil die Verwaltung von Sitzungen und Sitzungsstatus einfach zu unpraktisch ist.
Die zweite Option ist optimistisches Sperren. Bei diesem Ansatz fügen Sie der Zeile eine Versionsnummer/einen Zeitstempel hinzu. Sie wählen diese Versionsnummer/Zeitstempel, wenn Sie die Daten abfragen. Dann verwenden Sie dies in Ihrem WHERE
-Klausel, wenn Sie später die Aktualisierung durchführen und überprüfen, wie viele Zeilen tatsächlich geändert wurden. Wenn Sie genau eine Zeile ändern, wissen Sie, dass sich die Zeile seit dem Lesen nicht geändert hat. Wenn Sie 0 Zeilen ändern, wissen Sie, dass sich die Zeile geändert hat, und Sie können den Fehler behandeln.
So würden Sie beispielsweise die Daten zusammen mit der Versionsnummer auswählen
SELECT address_line1, city, state, zip, version
FROM addressTable
WHERE address_id = `<<some key>>`
Wenn Sie bereit waren, das Update durchzuführen, würden Sie so etwas tun, wobei Sie die version
verwenden in Ihrem UPDATE
und einen Fehler ausgeben, wenn sich die Zeile geändert hat
UPDATE addressTable
SET address_line1 = `<<new address line 1>>`,
city = `<<new city>>`,
state = `<<new state>>`,
zip = `<<new zip>>`,
version = version + 1
WHERE address_id = `<<some key>>`
AND version = `<<version you read initially>>`
IF( SQL%ROWCOUNT = 0 )
THEN
-- Darn. The row must have changed since you read it. Do something to
-- alert the user. Most likely, the application will need to re-query the
-- data to see what the address has been changed to and then ask the user
-- whether they want to re-apply the changes.
RAISE_APPLICATION_ERROR( -20001, 'Oops, the row has changed since you read it.' );
END IF;
Ihre Anwendung würde dann etwas Sinnvolles mit dem Fehler machen. Normalerweise würde das bedeuten, die Daten erneut abzufragen, dem Benutzer die Änderungen zu präsentieren und ihn zu fragen, ob er seine Änderungen trotzdem übernehmen möchte. Wenn ich zum Beispiel eine Adresse lese und beginne zu bearbeiten, zum Mittagessen gehe, mein Kollege sich anmeldet, dieselbe Adresse liest, einige Änderungen vornimmt und speichert, dann zurückkehre und versuche, meine Änderungen zu speichern, würde es im Allgemeinen Sinn machen um mir etwas zu zeigen, das mir mitteilt, dass mein Kollege die Adresse bereits in etwas Neues geändert hat – möchte ich mit der Bearbeitung fortfahren oder sie verwerfen.