In dieser praktischen Einführung werden Sie das Auftreten einer Phantomzeile beobachten können.
Damit diese praktische Einführung funktioniert, darf die Option Datenbanksperren automatisch freigeben in Interactive SQL (Extras » Optionen » SQL Anywhere) nicht aktiviert sein.
Starten Sie zwei Instanzen von Interactive SQL. Siehe die Schritte 1 bis 4 unter Praktische Einführung: Nicht-wiederholbare Lesevorgänge
Setzen Sie die Isolationsstufe im Fenster des "Sales Managers" auf 2, indem Sie den folgenden Befehl ausführen:
SET TEMPORARY OPTION isolation_level = 2; |
Stellen Sie die Isolationsstufe im Fenster des "Accountant" auf 2, indem Sie den folgenden Befehl ausführen:
SET TEMPORARY OPTION isolation_level = 2; |
Geben Sie im Fenster des "Accountant" folgenden Befehl ein, um alle Abteilungen aufzulisten:
SELECT * FROM Departments ORDER BY DepartmentID; |
DepartmentID | DepartmentName | DepartmentHeadID |
---|---|---|
100 | R & D | 501 |
200 | Sales | 902 |
300 | Finance | 1293 |
400 | Marketing | 1576 |
500 | Shipping | 703 |
Der "Sales Manager" beschließt, eine neue Abteilung aufzubauen, die sich auf den ausländischen Markt konzentriert. Philip Chin, der die Mitarbeiternummer (EmployeeID) 129 hat, leitet die neue Abteilung.
INSERT INTO Departments (DepartmentID, DepartmentName, DepartmentHeadID) VALUES(600, 'Foreign Sales', 129); |
COMMIT; |
Der letzte Befehl erstellt den Eintrag für die neue Abteilung ("Foreign Sales"). Sie erscheint als neue Zeile am Ende der Tabelle im Fenster des "Sales Managers".
Geben Sie im Fenster des "Sales Managers" folgenden Befehl ein, um alle Abteilungen aufzulisten:
SELECT * FROM Departments ORDER BY DepartmentID; |
DepartmentID | DepartmentName | DepartmentHeadID |
---|---|---|
100 | R & D | 501 |
200 | Sales | 902 |
300 | Finance | 1293 |
400 | Marketing | 1576 |
500 | Shipping | 703 |
600 | Foreign Sales | 129 |
Der "Accountant" weiß aber nichts von der neuen Abteilung. Bei Isolationsstufe 2 bringt der Datenbankserver Sperren an, um zu gewährleisten, dass sich keine Zeile verändert, bringt aber keine Sperren an, die verhindern, dass andere Transaktionen neue Zeilen einfügen.
Der "Accountant" findet die neue Zeile nur, wenn er noch einmal den SELECT-Befehl ausführt. Führen Sie im Fenster des "Accountants" noch einmal den SELECT-Befehl aus. Sie sehen nun die neue Zeile, die der Tabelle hinzugefügt wurde.
SELECT * FROM Departments ORDER BY DepartmentID; |
DepartmentID | DepartmentName | DepartmentHeadID |
---|---|---|
100 | R & D | 501 |
200 | Sales | 902 |
300 | Finance | 1293 |
400 | Marketing | 1576 |
500 | Shipping | 703 |
600 | Foreign Sales | 129 |
Die neue Zeile wird als Phantomzeile bezeichnet, da sie vom Blickwinkel des "Accountants" aus wie eine Erscheinung aus dem Nichts aufgetaucht ist. Der "Accountant" ist auf Isolationsstufe 2 verbunden. Auf dieser Stufe setzt der Datenbankserver nur Sperren für Zeilen, die er verwendet. Die anderen Zeilen bleiben unberührt, daher hält den "Sales Manager" nichts davon ab, eine neue Zeile einzufügen.
Der "Accountant" möchte in Zukunft solche Überraschungen vermeiden und erhöht die Isolation seiner gegenwärtigen Transaktion auf Stufe 3. Geben Sie für den Accountant folgende Befehle ein:
SET TEMPORARY OPTION isolation_level = 3; SELECT * FROM Departments ORDER BY DepartmentID; |
Der "Sales Manager" möchte gerne eine zweite Abteilung hinzufügen, die sich auf Verkaufsinitiativen für Großkunden konzentriert. Führen Sie den folgenden Befehl im Fenster des "Sales Managers" aus:
INSERT INTO Departments (DepartmentID, DepartmentName, DepartmentHeadID) VALUES(700, 'Major Account Sales', 902); |
Während der Ausführung wird das Fenster des "Sales Managers" angehalten, da die Sperren des "Accountant" den Befehl blockieren. Klicken Sie in der Symbolleiste auf SQL-Anweisung unterbrechen (oder wählen Sie SQL » Stopp), um diesen Eintrag zu unterbrechen.
Um zu vermeiden, dass die SQL Anywhere-Beispieldatenbank geändert wird, sollten Sie die unvollständige Transaktion zurücksetzen, welche die Zeile "Major Account Sales" einfügt, und eine zweite Transaktion benutzen, um die Abteilung "Foreign Sales" zu löschen.
Führen Sie den folgenden Befehl im Fenster "Sales Manager" aus, um die letzte, unvollständige Transaktion zurückzusetzen:
ROLLBACK; |
Führen Sie im Fenster "Sales Manager" die folgenden beiden Anweisungen aus, um die Zeile zu löschen, die Sie zuvor eingefügt haben, und diesen Vorgang festzuschreiben.
DELETE FROM Departments WHERE DepartmentID = 600; |
COMMIT; |
Als der "Accountant" die Isolationsstufe auf 3 erhöhte und noch einmal alle Zeilen in der Tabelle "Departments" auswählte, brachte der Datenbankserver Anti-Einfügesperren für jede Zeile der Tabelle an. Außerdem setzte er eine zusätzliche Phantomsperre, um Eingaben am Ende der Tabelle zu blockieren. Als der "Sales Manager" versuchte, am Ende der Tabelle eine neue Zeile einzufügen, war es diese letzte Sperre, die seinen Befehl blockierte.
Der Befehl des "Sales Managers" wurde blockiert, obwohl der "Sales Manager" noch immer mit Isolationsstufe 2 verbunden ist. Der Datenbankserver platziert Anti-Einfügesperren, wie Lesesperren, entsprechend den Anforderungen der Isolationsstufe und den Anweisungen jeder Transaktion. Sobald diese Sperren angebracht sind, müssen sie von allen anderen gleichzeitig ablaufenden Transaktionen respektiert werden.
Weitere Hinweise zu Sperren finden Sie unter Funktionsweise von Sperren.
Sie können die Snapshot-Isolationsstufe verwenden, um die Konsistenz auf der gleichen Stufe aufrechtzuerhalten wie auf Isolationsstufe 3, ohne dass es zu Blockierungen kommt. Der Befehl des "Sales Managers" wird nicht blockiert, und der "Accountant" sieht keine Phantomzeile.
Falls bisher noch nicht geschehen, führen Sie die Schritte 1 bis 4 von Praktische Einführung: Phantomzeilen durch, die beschreiben, wie Sie zwei Instanzen von Interactive SQL starten.
Aktivieren Sie die Snapshot-Isolation für den "Accountant", indem Sie den folgenden Befehl ausführen.
SET OPTION PUBLIC. allow_snapshot_isolation = 'On'; SET TEMPORARY OPTION isolation_level = snapshot; |
Geben Sie im Fenster des "Accountant" folgenden Befehl ein, um alle Abteilungen aufzulisten:
SELECT * FROM Departments ORDER BY DepartmentID; |
DepartmentID | DepartmentName | DepartmentHeadID |
---|---|---|
100 | R & D | 501 |
200 | Sales | 902 |
300 | Finance | 1293 |
400 | Marketing | 1576 |
500 | Shipping | 703 |
Der "Sales Manager" beschließt, eine neue Abteilung aufzubauen, die sich auf den ausländischen Markt konzentriert. Philip Chin, der die Mitarbeiternummer (EmployeeID) 129 hat, leitet die neue Abteilung.
INSERT INTO Departments (DepartmentID, DepartmentName, DepartmentHeadID) VALUES(600, 'Foreign Sales', 129); COMMIT; |
Der letzte Befehl erstellt den Eintrag für die neue Abteilung ("Foreign Sales"). Sie erscheint als neue Zeile am Ende der Tabelle im Fenster des "Sales Managers".
SELECT * FROM Departments ORDER BY DepartmentID; |
DepartmentID | DepartmentName | DepartmentHeadID |
---|---|---|
100 | R & D | 501 |
200 | Sales | 902 |
300 | Finance | 1293 |
400 | Marketing | 1576 |
500 | Shipping | 703 |
600 | Foreign Sales | 129 |
Der "Accountant" kann seine Abfrage erneut ausführen und sieht die neue Zeile nicht, da die Transaktion nicht beendet wurde.
SELECT * FROM Departments ORDER BY DepartmentID; |
DepartmentID | DepartmentName | DepartmentHeadID |
---|---|---|
100 | R & D | 501 |
200 | Sales | 902 |
300 | Finance | 1293 |
400 | Marketing | 1576 |
500 | Shipping | 703 |
Der "Sales Manager" möchte gerne eine zweite Abteilung hinzufügen, die sich auf Verkaufsinitiativen für Großkunden konzentriert. Führen Sie den folgenden Befehl im Fenster des "Sales Managers" aus:
INSERT INTO Departments (DepartmentID, DepartmentName, DepartmentHeadID) VALUES(700, 'Major Account Sales', 902); |
Die Änderung des "Sales Managers" wird nicht blockiert, da der "Accountant" die Snapshot-Isolation benutzt.
Der "Accountant" muss seine Snapshot-Transaktion beenden, um die Änderungen zu sehen, die der "Sales Manager" in der Datenbank festgeschrieben hat.
COMMIT; SELECT * FROM Departments ORDER BY DepartmentID; |
Nun sieht der "Accountant" die Abteilung "Foreign Sales", nicht aber die Abteilung "Major Account Sales".
DepartmentID | DepartmentName | DepartmentHeadID |
---|---|---|
100 | R & D | 501 |
200 | Sales | 902 |
300 | Finance | 1293 |
400 | Marketing | 1576 |
500 | Shipping | 703 |
600 | Foreign Sales | 129 |
Um zu vermeiden, dass die SQL Anywhere-Beispieldatenbank geändert wird, sollten Sie die unvollständige Transaktion zurücksetzen, welche die Zeile "Major Account Sales" einfügt, und eine zweite Transaktion benutzen, um die Abteilung "Foreign Sales" zu löschen.
Führen Sie den folgenden Befehl im Fenster "Sales Manager" aus, um die letzte, unvollständige Transaktion zurückzusetzen:
ROLLBACK; |
Führen Sie im Fenster "Sales Manager" die folgenden beiden Anweisungen aus, um die Zeile zu löschen, die Sie zuvor eingefügt haben, und diesen Vorgang festzuschreiben.
DELETE FROM Departments WHERE DepartmentID = 600; |
COMMIT; |
Kommentieren Sie diese Seite in DocCommentXchange. Senden Sie uns Feedback über diese Seite via E-Mail. |
Copyright © 2009, iAnywhere Solutions, Inc. - SQL Anywhere 11.0.1 |