Zunächst einmal verhindert das Sperren einer Tabelle nicht, dass eine andere Sitzung SELECT
ausgibt Aussagen gegen die Daten.
In Sitzung 1, wenn ich die Tabelle sperre
SQL> lock table foo in exclusive mode;
Table(s) Locked.
Ich kann dann Sitzung 2 starten und die Daten nach Belieben abfragen
SQL> select * from foo;
COL1
----------
1
1
In Oracle blockieren Writer keine Reader, sodass Sie niemals verhindern können, dass eine andere Sitzung die Daten in einer Tabelle abfragt.
Es hört sich so an, als ob Sie versuchen, eine pessimistische Sperre zu implementieren. Anstatt die Tabelle zu sperren, führen Sie in diesem Fall ein SELECT FOR UPDATE
durch die den jeweiligen Eintrag sperrt, den Sie bearbeiten möchten. Solange alle anderen Sitzungen auch versuchen, ein SELECT FOR UPDATE
durchzuführen (abhängig von der Oracle-Version, möglicherweise Hinzufügen des SKIP LOCKED
Qualifier und/oder das WAIT
Qualifikation). Dadurch wird die bestimmte Zeile gesperrt, die Sie verarbeiten, und die zweite Sitzung kann entweder eine andere Zeile auswählen oder eine Zeitüberschreitung feststellen oder feststellen, dass je nach den Besonderheiten der Implementierung keine Zeilen zu verarbeiten sind. Dabei wird die Tabelle nicht gesperrt.
Die einzige Möglichkeit, eine Sperre freizugeben, besteht darin, dass die Sitzung, die sie erworben hat, sie freigibt (im Allgemeinen durch Beenden der Transaktion) oder dass die Sitzung, die sie erworben hat, beendet wird. Wenn die Clientanwendung noch ausgeführt wird, aber nichts unternimmt, um die Sperre aufzuheben oder die Sitzung zu beenden, wird die Sperre auf unbestimmte Zeit aufrechterhalten. Ein DBA müsste die Sitzung explizit beenden, die Transaktion rückgängig machen und die Sperre freigeben, um das System wieder zum Laufen zu bringen. Wenn die Clientanwendung nicht mehr ausgeführt wird oder zumindest nicht mehr reagiert (mir ist immer noch nicht klar, welches Fehlerszenario Sie besprechen), ist es möglich, dass das Aktivieren der Dead-Connection-Erkennung (DCD) über die 'SQLNET.EXPIRE_TIME'-Parameter auf Datenbankebene würde dazu führen, dass die Datenbank feststellt, dass der Client nicht antwortet, und die Sitzung automatisch beendet, die Transaktion rückgängig macht und die Sperre aufhebt.
Wenn es jedoch mehrere Sitzungen gibt, die Daten verarbeiten, ist es im Allgemeinen viel vorzuziehen, irgendeine Form von optimistischem Sperren zu verwenden. Andernfalls entwerfen Sie ein System, bei dem der DBA unweigerlich dringend Sitzungen finden und beenden muss, damit die Geschäftsbenutzer wieder arbeiten können, und das immer mehr Eingriffe erfordert, je ausgelasteter es wird. Das ist nichts, was DBAs gerne tun, und nichts, worüber sich Geschäftsanwender gerne beschweren. Ein einfaches optimistisches Sperrschema wäre so etwas wie
- Wählen Sie einen zu verarbeitenden Schlüssel und eine Art Datum aus, das angibt, wann die Zeile zuletzt aktualisiert wurde.
- Aktualisieren Sie eine Statusspalte auf "in Bearbeitung", damit andere Sitzungen nicht versuchen, dieselbe Zeile zu verarbeiten.
- Bearbeiten Sie den Eintrag in Ihrer Bewerbung
- Wenn Sie mit der Verarbeitung fertig sind, aktualisieren Sie die Daten mit dem Schlüssel und der Zeit, die Sie im ersten Schritt ausgewählt haben. Wenn Sie 1 Zeile aktualisieren, wissen Sie, dass keine andere Sitzung die betreffenden Daten geändert hat, seit Sie sie ausgewählt haben. Wenn Sie 0 Zeilen aktualisieren, wissen Sie, dass eine andere Sitzung die Daten geändert hat, seit Sie sie ausgewählt haben.
Mit dieser Art von Architektur ist es relativ einfach, die Datenbank abzufragen, um zu sehen, welche Zeilen verarbeitet werden, und um beispielsweise einen Job zu haben, der die Statusspalte nach einiger Zeit auf „unverarbeitet“ zurücksetzt, wenn der Client dies nicht getan hat fertig. Für andere Sitzungen ist es relativ einfach, eine andere Zeile zur Verarbeitung auszuwählen. Und es ist relativ sicher, wenn die Anwendung beispielsweise für ein paar Stunden einfriert und sich dann erholt, da sie erst nach Abschluss der Verarbeitung feststellt, dass eine andere Sitzung die Zeile bereits erneut verarbeitet hat.