Das Beispiel in Praktische Einführung: Dirty Reads hat den ersten Typ von Inkonsistenz vorgeführt, nämlich Dirty Reads. In diesem Beispiel führte ein "Accountant" eine Berechnung aus, während der "Sales Manager" dabei war, einen Preis heraufzusetzen. Die Berechnung des "Accountants" beruhte auf fehlerhaften Daten, die der "Sales Manager" eingegeben hatte und gerade korrigieren wollte.
Das folgende Beispiel zeigt eine andere Art von Inkonsistenz: Nicht-wiederholbare Lesevorgänge. In diesem Beispiel spielen Sie die Rolle derselben zwei Mitarbeiter, die die SQL Anywhere-Beispieldatenbank gleichzeitig benutzen. Der "Sales Manager" möchte für Plastik-Schirmmützen einen neuen Preis anbieten. Der "Accountant" will die Preise für einige Waren auf einer kürzlich getätigten Bestellung überprüfen.
Dieses Beispiel beginnt mit beiden Verbindungen auf Isolationsstufe 1 und nicht auf Isolationsstufe 0, was die Standardisolation für die Beispieldatenbank wäre, die mit SQL Anywhere bereitgestellt wird. Indem die Isolationsstufe auf 1 gesetzt wird, vermeiden Sie die Art von Inkonsistenz, die in der vorherigen praktischen Einführung aufgezeigt wurde, nämlich Dirty Reads.
Damit diese praktische Einführung funktioniert, darf die Option Datenbanksperren automatisch freigeben in Interactive SQL (Extras » Optionen » SQL Anywhere) nicht aktiviert sein.
Starten Sie Interactive SQL.
Im Fenster Verbinden stellen Sie als "Sales Manager" eine Verbindung mit der SQL Anywhere-Beispieldatenbank her.
Im Feld ODBC-Datenquellenname wählen Sie SQL Anywhere 11 Demo.
Klicken Sie auf das Register Erweitert und geben Sie Sales Manager in das Feld ConnectionName ein.
Klicken Sie auf OK.
Starten Sie eine zweite Instanz von Interactive SQL.
Im Fenster Verbinden stellen Sie als "Accountant" eine Verbindung mit der SQL Anywhere-Beispieldatenbank her.
Im Feld ODBC-Datenquellenname wählen Sie SQL Anywhere 11 Demo.
Klicken Sie auf das Register Erweitert und geben Sie Accountant in das Feld ConnectionName ein.
Klicken Sie auf OK.
Setzen Sie die Isolationsstufe für die Verbindung des "Accountant" auf 1, indem Sie den folgenden Befehl ausführen.
SET TEMPORARY OPTION isolation_level = 1; |
Setzen Sie die Isolationsstufe im Fenster des "Sales Managers" auf 1, indem Sie den folgenden Befehl ausführen:
SET TEMPORARY OPTION isolation_level = 1; |
Der "Accountant" beschließt, die Preise für die Schirmmützen (Visors) aufzulisten. Führen Sie als "Accountant" folgenden Befehl aus:
SELECT ID, Name, UnitPrice FROM Products; |
ID | Name | UnitPrice |
---|---|---|
300 | Tee Shirt | 9.00 |
301 | Tee Shirt | 14.00 |
302 | Tee Shirt | 14.00 |
400 | Baseball Cap | 9.00 |
401 | Baseball Cap | 10.00 |
500 | Visor | 7.00 |
501 | Visor | 7.00 |
... | ... | ... |
Der "Sales Manager" beschließt, für die Schirmmützen einen neuen Verkaufspreis festzusetzen. Führen Sie als "Sales Manager" folgenden Befehl aus:
SELECT ID, Name, UnitPrice FROM Products WHERE Name = 'Visor'; UPDATE Products SET UnitPrice = 5.95 WHERE ID = 501; COMMIT; SELECT ID, Name, UnitPrice FROM Products WHERE Name = 'Visor'; |
ID | Name | UnitPrice |
---|---|---|
500 | Visor | 7.00 |
501 | Visor | 5.95 |
Vergleichen Sie den Preis für die Schirmmützen (Visor) im Fenster des "Sales Managers" mit dem Preis für die gleichen Schirmmützen im Fenster des "Accountants". Der "Accountant" führt die SELECT-Anweisung erneut aus und sieht den neuen Verkaufspreis des "Sales Managers".
SELECT ID, Name, UnitPrice FROM Products; |
ID | Name | UnitPrice |
---|---|---|
300 | Tee Shirt | 9.00 |
301 | Tee Shirt | 14.00 |
302 | Tee Shirt | 14.00 |
400 | Baseball Cap | 9.00 |
401 | Baseball Cap | 10.00 |
500 | Visor | 7.00 |
501 | Visor | 5.95 |
... | ... | ... |
Diese Inkonsistenz wird nicht-wiederholbarer Lesevorgang genannt, da der "Accountant" ein zweites Mal die gleiche SELECT-Anweisung in der gleichen Transaktion ausführt und nicht mehr dasselbe Ergebnis erhält.
Hätte der "Accountant" seine Transaktion mit einem COMMIT- oder ROLLBACK-Befehl beendet, bevor er wiederum den SELECT-Befehl angewendet hätte, wäre die ganze Sache anders verlaufen. Die Datenbank steht für die gleichzeitige Verwendung mehrerer Benutzer zur Verfügung, und es ist absolut zulässig, dass jemand die Werte vor oder nach der Transaktion des "Accountants" verändert. Die geänderten Ergebnisse sind nur deshalb inkonsistent, da die Änderungen während der Transaktion geschahen. Ein solches Ereignis macht das Schema unserialisierbar.
Der "Accountant" bemerkt dieses Verhalten und beschließt, dass er in Zukunft nicht mehr will, dass sich die Preise ändern, während er sie sich ansieht. Nicht wiederholbare Lesevorgänge werden auf Isolationsstufe 2 eliminiert. Führen Sie als "Accountant" folgende Anweisungen aus:
SET TEMPORARY OPTION isolation_level = 2; SELECT ID, Name, UnitPrice FROM Products; |
Der "Sales Manager" entscheidet, dass es besser ist, mit dem Abverkauf der Schirmmützen bis zur nächsten Woche zu warten, damit er den niedrigeren Preis nicht für eine große Bestellung, die er für den nächsten Tag erwartet, hergeben muss. Versuchen Sie, in seinem Fenster die folgenden Anweisungen auszuführen. Die Ausführung des Befehls beginnt und plötzlich scheint sein Fenster einzufrieren.
UPDATE Products SET UnitPrice = 7.00 WHERE ID = 501; |
Der Datenbankserver muss auf Isolationsstufe 2 wiederholbare Lesevorgänge garantieren. Da der "Accountant" Isolationsstufe 2 verwendet, setzt der Datenbankserver eine Lesesperre auf jede Zeile der Tabelle "Products", die vom "Accountant" gelesen wird. Wenn der "Sales Manager" versucht, den Preis zurück zu ändern, muss seine Transaktion eine Schreibsperre für die Zeile mit den Schirmmützen in der Tabelle "Products" setzen. Da Schreibsperren Exklusivsperren sind, muss seine Transaktion warten, bis die Transaktion des "Accountants" die Lesesperre freigibt.
Der "Accountant" ist mit der Durchsicht der Preise fertig. Er möchte nicht riskieren, die Datenbank unbeabsichtigt zu ändern, also beendet er seine Transaktion mit einem ROLLBACK-Befehl.
ROLLBACK; |
Wenn der Datenbankserver diese Anweisung ausführt, wird die Transaktion des "Sales Manager" abgeschlossen.
ID | Name | UnitPrice |
---|---|---|
500 | Visor | 7.00 |
501 | Visor | 7.00 |
Der "Sales Manager" kann nun seine Transaktion abschließen. Er will seine Änderung festschreiben und den ursprünglichen Preis wiederherstellen.
COMMIT; |
Als Sie die Isolation des "Accountants" von Stufe 1 auf Stufe 2 erhöht haben, hat der Datenbankserver Lesesperren verwendet, wo es vorher keine gab. Allgemein gilt, dass jede Isolationsstufe durch die benötigten Sperrentypen charakterisiert wird und wie Sperren behandelt werden, die von anderen Transaktionen kommen.
Bei Isolationsstufe 0 benötigt der Datenbankserver nur Schreibsperren. Er verwendet diese Sperren, um zu gewährleisten, dass nicht zwei Transaktionen einander widersprechende Änderungen durchführen. So setzt zum Beispiel eine Stufe 0-Transaktion eine Schreibsperre für eine Zeile, bevor sie sie aktualisiert oder löscht, und jede neue Zeile wird mit einer bereits eingerichteten Schreibsperre eingefügt.
Stufe 0-Transaktionen führen keine Überprüfung der Zeilen durch, die sie lesen. Wenn zum Beispiel eine Stufe 0-Transaktion eine Zeile liest, überprüft sie nicht, welche Sperren möglicherweise von anderen Transaktionen für diese Zeile gesetzt wurden. Da keine Überprüfungen notwendig sind, sind Stufe 0-Transaktionen besonders schnell. Diese Geschwindigkeit geht auf Kosten der Konsistenz. Jedes Mal, wenn eine Zeile gelesen wird, für die es eine Schreibsperre durch eine andere Transaktion gibt, laufen Sie Gefahr, nicht festgeschriebene Daten zu erhalten.
Bei Stufe 1 überprüfen Transaktionen, ob Schreibsperren vorliegen, bevor sie eine Zeile lesen. Obwohl hierfür ein Arbeitsgang mehr notwendig ist, ist bei diesen Transaktionen sichergestellt, dass sie nur festgeschriebene Daten lesen. Wiederholen Sie die erste praktische Einführung, und zwar mit der Isolationsstufe 1 anstatt 0. Sie werden feststellen, dass der "Accountant" mit seiner Berechnung nicht fortfahren kann, während die Transaktion des "Sales Managers", der die Preise der T-Shirts aktualisiert, nicht abgeschlossen wird.
Als der "Accountant" seine Isolation auf Stufe 2 erhöhte, begann der Datenbankserver, Lesesperren zu verwenden. Ab da setzte er eine Lesesperre für seine Transaktion, und zwar für jede Zeile, die der "Accountant" auswählte.
In der vorigen praktischen Einführung fror das Fenster des "Sales Managers" während der Ausführung des UPDATE-Befehls ein. Der Datenbankserver begann den Befehl auszuführen, als er feststellte, dass die Transaktion des "Accountants" eine Lesesperre für die Zeile gesetzt hat, die der "Sales Manager" ändern musste. An diesem Punkt setzte der Datenbankserver einfach mit der Ausführung der Aktualisierung aus. Sobald der "Accountant" seine Transaktion mit dem ROLLBACK-Befehl abgeschlossen hatte, gab der Datenbankserver seine Sperren automatisch frei. Da es keine weiteren Hindernisse mehr gab, schloss er die Ausführung des UPDATE-Befehls des "Sales Managers" ab.
Im Allgemeinen tritt ein Sperrenkonflikt auf, wenn eine Transaktion versucht, eine Exklusivsperre für eine Zeile zu setzen, an der eine andere Transaktion eine Sperre hält, oder versucht, eine gemeinsame Sperre für eine Zeile zu setzen, in der eine andere Transaktion eine Exklusivsperre hält. Die Transaktion muss warten, bis eine andere Transaktion abgeschlossen ist. Die Transaktion, die warten muss, wird als blockierte Transaktion bezeichnet.
Wenn der Datenbankserver einen Sperrenkonflikt erkennt, der verhindert, dass eine Transaktion sofort abläuft, kann er entweder die Ausführung der Transaktion aussetzen, oder die Transaktion beenden, Änderungen zurücksetzen und einen Fehler zurückgeben. Sie kontrollieren den Vorgang, indem Sie die Option "blocking" einstellen. Ist diese Option auf "On" gesetzt, so wartet die zweite Transaktion wie in dem zuvor angeführten Beispiel.
Weitere Hinweise zur Blocking-Option finden Sie unter Die Blocking-Option.
Sie können die Snapshot-Isolation auch verwenden, um das Vermeiden von Blockierungen zu unterstützen. Da Transaktionen, welche die Snapshot-Isolation verwenden, nur festgeschriebene Daten erkennen, wird die Transaktion des "Sales Managers" durch die Transaktion des "Accountant" nicht blockiert.
Starten Sie Interactive SQL.
Im Fenster Verbinden stellen Sie als "Sales Manager" eine Verbindung mit der SQL Anywhere-Beispieldatenbank her.
Im Feld ODBC-Datenquellenname wählen Sie SQL Anywhere 11 Demo.
Klicken Sie auf das Register Erweitert und geben Sie Sales Manager in das Feld ConnectionName ein.
Klicken Sie auf OK.
Starten Sie eine zweite Instanz von Interactive SQL.
Im Fenster Verbinden stellen Sie als "Accountant" eine Verbindung mit der SQL Anywhere-Beispieldatenbank her.
Im Feld ODBC-Datenquellenname wählen Sie SQL Anywhere 11 Demo.
Klicken Sie auf das Register Erweitert und geben Sie Accountant in das Feld ConnectionName ein.
Klicken Sie auf OK.
Führen Sie die folgenden Anweisungen aus, um die Snapshot-Isolation für die Datenbank zu aktivieren und festzulegen, dass die Snapshot-Isolationsstufe benutzt wird:
SET OPTION PUBLIC.allow_snapshot_isolation = 'On'; SET TEMPORARY OPTION isolation_level = snapshot; |
Der "Accountant" beschließt, die Preise für die Schirmmützen (Visors) aufzulisten. Führen Sie als "Accountant" folgenden Befehl aus:
SELECT ID, Name, UnitPrice FROM Products ORDER BY ID; |
ID | Name | UnitPrice |
---|---|---|
300 | Tee Shirt | 9.00 |
301 | Tee Shirt | 14.00 |
302 | Tee Shirt | 14.00 |
400 | Baseball Cap | 9.00 |
401 | Baseball Cap | 10.00 |
500 | Visor | 7.00 |
501 | Visor | 7.00 |
... | ... | ... |
Der "Sales Manager" beschließt, für die Schirmmützen einen neuen Verkaufspreis festzusetzen. Führen Sie als "Sales Manager" folgenden Befehl aus:
UPDATE Products SET UnitPrice = 5.95 WHERE ID = 501; COMMIT; SELECT ID, Name, UnitPrice FROM Products WHERE Name = 'Visor'; |
Der "Accountant" führt seine Abfrage erneut aus und sieht die Preisänderung nicht, da die Daten, die zum Zeitpunkt des ersten Lesevorgangs festgeschrieben waren, für die Transaktion benutzt werden.
SELECT ID, Name, UnitPrice FROM Products; |
Setzen Sie als "Sales Manager" den Preis für die Plastik-Schirmmützen wieder auf den Originalpreis zurück.
UPDATE Products SET UnitPrice = 7.00 WHERE ID = 501; COMMIT; |
Der Datenbankserver setzt keine Lesesperren auf die Zeilen in der Tabelle "Products", die der "Accountant" liest, da der "Accountant" einen Snapshot der festgeschriebenen Daten sieht, der angefertigt wurde, bevor der "Sales Manager" Änderungen an der Tabelle "Products" durchgeführt hat.
Der "Accountant" ist mit der Durchsicht der Preise fertig. Er möchte nicht riskieren, die Datenbank unbeabsichtigt zu ändern, also beendet er seine Transaktion mit einem ROLLBACK-Befehl.
ROLLBACK; |
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 |