Wesentlich für das Arbeiten mit Datenbanken sind konsistente Datenbestände! Folgerung: es muss sichergestellt werden, dass Datenmanipulationen von Benutzern immer in einem erneut konsistenten Zustand der Datenbank resultieren! aber: einzelne Datenmanipulationsoperationen erzeugen in der Regel einen inkonsistenten Zustand! Beispiel (Bezug: eine Personen-Datenbank): Für die Personen-Datenbank gibt es die Geschäftsregel, dass alle Personen in der Datenbank mindestens eine gültige Adresse, einen gültigen Ausbildungs- und einen gültigen Berufsdatensatz haben! Folge: Das insert eines Personendatensatzes überführt die Datenbank in einen inkonsistenten Zustand! Erst wenn alle übrigen Datensätze zu Adresse, Beruf und Ausbildung eingefügt wurden, besteht wieder Konsistenz! 1
Deshalb arbeiten Datenbanken mit dem Transaktionskonzept: Definition: Eine Transaktion ist eine Menge von Datenmanipulationsoperationen, die eine Datenbank von einem konsistenten Zustand in einen erneut konsistenten Zustand überführt Transaktionen haben einen definierten Anfang: begin oder einfach die erste Operation (SQL-statement) Transaktionen haben ein definiertes Ende: erfolgreich: erfolglos: commit; rollback; oder abort; 2
Deshalb arbeiten Datenbanken mit dem Transaktionskonzept: Transaktionsbeginn! insert into person values(persnr_seq.nextval, 'Meier', 'Kurt', '12.12.1980', 'M'); insert into adresse values(adrnr_seq.nextval, '12345', 'Teststadt', 'Teststr.12', 'P', persnr_seq.currval); insert into adresse values(adrnr_seq.nextval, '11223', 'Dudenhausen', 'Kirchweg 9', 'D', persnr_seq.currval); insert into hobbies values(hnr_seq.nextval, 'Schwimmen', persnr_seq.currval); insert into hobbies values(hnr_seq.nextval, 'Tischtennis', persnr_seq.currval); insert into ausbildungen values(anr_seq.nextval, 'Gymnasium', '01.01.1990', '17.04.1997', 'Mittlere Reife', '17.04.1997', persnr_seq.currval); insert into ausbildungen values(anr_seq.nextval, 'Bäckerlehre', '01.01.1998', '31.12.1999', 'Geselle', '20.5.2000', persnr_seq.currval); insert into beruf values(bnr_seq.nextval, 'Bäcker Catering', '01.10.2000','31.12.2003', 2100, persnr_seq.currval); insert into beruf values(bnr_seq.nextval, 'Bäcker Meier', '01.01.2004', Null, 4350, persnr_seq.currval); commit; Transaktionsende! 3
Die Transaktionsstatements commit und rollback bekommen im Laufe dieser Untersuchungen weitere Bedeutung. Hier zeigen sie zunächst einmal lediglich das Ende der Transaktion an!! Aus der Forderung, konsistente Zustände zu erzeugen, resultieren im klassischen Fall 4 weitere Bedingungen an Transaktionen: die ACID-Bedingungen: A (Atomicy): Jede Transaktion wird vollständig oder gar nicht ausgeführt! C (Consistency):Jede Transaktion erzeugt einen konsistenten Datenbankzustand! I (Isolation): D (Durability): Die von einer Transaktion benötigten Daten müssen vor der Konsistenz gefährdenden Nutzung durch parallel laufende Transaktionen geschützt werden. Das Ergebnis einer erfolgreichen Transaktion muss physisch in der Datenbank vorhanden sein. 4
Anmerkungen: 1. Es gibt andere (nicht-klassische) Transaktionskonzepte, in denen die ACID-Bedingungen verändert oder erweitert wurden! 2. Aus der Bedingung D der ACID-Bedingungen ergibt sich eine erste Erweiterung der Bedeutung des commit-statements: commit ist zusätzlich der Befehl an das DBMS, spätestens jetzt die in dieser Transaktion veränderten Daten physisch in die Datenbank zu schreiben bzw. die bereits geschriebenen Daten als nicht mehr rollbackfähig zu kennzeichnen! 3. Bedingung A erfordert das rollback. Insbesondere folgt daraus auch, dass alle Werte von Datenmanipulationen vor und nach der Änderung in den Log-Dateien protokolliert werden müssen! 4. Die Verwaltung der Transaktionen in einer aktiven Datenbank übernimmt der Transaktionsmanager als Komponente des DBMS. 5
Anmerkungen: 5. Die Bedingung I (Isolation) macht in einem multi-user-umfeld die meisten Probleme und erfordert zur Einhaltung zusätzliche Konzepte und Mechanismen. Dies wird zusammengefasst unter dem Begriff Concurrency Control. 6. Die potentiell auftretenden Probleme im Zusammenhang mit der Verwaltung parallel arbeitender Transaktionen auf dem gleichen Datenbestand (Concurrency Control) sind zu den 4 klassischen Problemen kategorisiert worden: Phantome lost update dirty read unrepeatable read 7. In den folgenden Szenarien wird davon ausgegangen, dass alle Änderungen der Daten sofort für alle sichtbar werden, da keinerlei Schutzmechanismen implementiert sind! 6
Phantome: Ein Phantom ist ein Datenbankobjekt, das bzgl. eines Datenbankschemas existieren kann, aber bei einem Teil einer Transaktionsdauer nicht existiert! Beispiel: (Transaktion T1 teilt 10.000 Euro auf die aktuellen Gehälter aller Personen auf, Transaktion T2 fügt zwischendurch eine neue Person ein!) T1 T2 Declare X integer; Begin select count(*) into x from person; insert into Person(persnr, name) values(4711, Meier ); insert into beruf values(123,..., 2300.00); commit; update beruf set gehalt = gehalt + 10000/x where beendet is not null; commit; End; 7
Lost update: Zwei Transaktionen bearbeiten einen Datenbestand mit den Operationen r(x) (read) und/oder w(x) (write). Zur Demonstration wird angenommen, dass die Operation w(x) bedeutet, dass x auf x+1 verändert und dieser neue Wert geschrieben wird: Ergebnis: T1 Zeit T2 x Begin T1 1 r1(x) 2 x = 10 3 Begin T2 4 r2(x) x = 10 w1(x) 5 x = 11 commit1 6 7 w2(x) x= 11 8 commit2 In der Datenbank steht der falsche Wert x = 11. Richtiger Wert: x = 12 Grund: Beide Transaktionen lesen den gleichen Wert, verändern ihn und schreiben ihn unabhängig voneinander in die Datenbank. 8
Dirty read: Zwei Transaktionen bearbeiten einen Datenbestand mit den Operationen r(x) (read) und/oder w(x) (write). Zur Demonstration wird angenommen, dass die Operation w(x) bedeutet, dass x auf x+1 verändert und dieser neue Wert geschrieben wird (alle Änderungen werden sofort für alle sichtbar!): Ergebnis: T1 Zeit T2 x Begin T1 1 r1(x) 2 x = 10 w1(x) 3 x= 11 4 Begin T2 5 r2(x) x = 11 6 w2(x) x = 12 rollback1 7 8 commit2 In der Datenbank steht der falsche Wert x = 12. Richtiger Wert: x = 11 Grund: Transaktion T2 liest einen Wert (x = 11), den es so nie in der Datenbank gegeben hat, da T1 zurückrollt. 9
Unrepeatable read: Zwei Transaktionen bearbeiten einen Datenbestand mit den Operationen r(x) (read) und/oder w(x) (write). T1 summiert Werte, T2 verschiebt Werte: T1 Zeit T2 Werte Begin T1 1 sum = 0 2 r1(x) 3 x = 40 r1(y) 4 y = 50 sum = sum + x 5 Sum = 40 sum = sum + y 6 Sum = 90 7 Begin T2 8 r2(z) z = 30 9 w2(z) z = z 10 = 20 10 r2(x) x = 40 11 w2(x) x = x + 10 = 50 12 commit2 r1(z) 13 z = 20 sum = sum + z 14 sum = 110 w1(sum) 15 commit1 16 10
Unrepeatable read: T1 Zeit T2 Werte Begin T1 1 sum = 0 2 r1(x) 3 x = 40 r1(y) 4 y = 50 sum = sum + x 5 Sum = 40 sum = sum + y 6 Sum = 90 7 Begin T2 8 r2(z) z = 30 9 w2(z) z = z 10 = 20 10 r2(x) x = 40 11 w2(x) x = x + 10 = 50 12 commit2 r1(z) 13 z = 20 sum = sum + z 14 sum = 110 w1(sum) 15 commit1 16 Ergebnis: In der Datenbank steht der falsche Wert sum = 110. Richtiger Wert: sum = 120. 11
Alle diese Verletzungen der Isolation-Bedingung können auftreten, falls das Datenbanksystem keine Konzepte und Mechanismen dagegen implementiert hat! Die Folge wäre, dass mit der Zeit die Datenbank nur noch inkonsistente Datenbestände enthält, also unbrauchbar geworden ist! Es ist also unbedingt erforderlich, die Isolation-Bedingung durch eigene Konzepte und Mechanismen zu erzwingen! Dazu dienen: Sperren Sperrprotokolle Erstellen serialisierbarer Ablaufpläne 12
Sperren: Im Standard-Transaktionskonzept sind zwei Arten von Sperren definiert: Lesesperren rlock(x): Bedeutung: Sperren des Objekts x im shared mode Die sperrende Transaktion darf das Objekt x nur lesen, nicht verändern. Alle anderen Transaktionen können das Objekt x höchstens zum Lesen sperren! Schreibsperren wlock(x): Bedeutung: Sperren des Objekts x im exclusive mode Die sperrende Transaktion darf das Objekt x lesen und verändern. Alle anderen Transaktionen können nicht auf das Objekt x zugreifen! Erlaubnistabelle: T1 \ T2 rlock wlock rlock 1 0 wlock 0 0 13
Lösung des dirty read - Problems durch Sperren: T1 Zeit T2 x Begin T1 1 wlock1(x) 2 r1(x) 3 x = 10 w1(x) 4 x= 11 unlock1(x) 5 rollback1 6 7 Begin T2 8 wlock2(x) 9 r2(x) x = 10 10 w2(x) x = 11 11 unlock2(x) 12 commit2 14
Am Beispiel der Lösung des dirty read Problems wird klar, dass zur Vermeidung der klassischen Probleme an die Transaktionsstatements commit und rollback / abort weitere Bedingungen zu knüpfen sind, denn, geschieht das nicht, ist weiterhin folgendes möglich: T1 Zeit T2 x Begin T1 1 wlock1(x) 2 r1(x) 3 x = 10 w1(x) 4 x= 11 unlock1(x) 5 7 Begin T2 8 wlock2(x) 9 r2(x) x = 11 10 w2(x) x = 12 rollback1 11 12 unlock2(x) 13 commit2 Zur Vermeidung muss also das Aufheben der Sperren an die Transaktionsstatements gebunden sein!! 15
Dies führt zur Definition verschiedener Sicherheitslevel (Isolationlevel), die für Transaktionen gesetzt werden können Höchstes Sicherheitslevel: serializable Bedeutung: Das Aufheben von Sperren ist an die statements commit bzw. rollback / abort gebunden. Folge: Für diese Transaktion ist das Auftreten eines Isolation-Problems garantiert ausgeschlossen! Unter diesem höchsten Sicherheitslevel gibt es eine Reihe abgestufter niedrigerer Level, je nachdem, welche klassischen Probleme zugelassen werden sollen oder nicht! 16
Sicherheitslevel (Isolationlevel), die für Transaktionen gesetzt werden können: READ UNCOMMITTED: READ COMMITTED: REPEATABLE READ: SERIALIZABLE: alle klassischen Probleme sind möglich unrepeatable reads und Phantome sind möglich nur noch Phantome sind möglich kein klassisches Problem ist mehr möglich Das Setzen und Lösen von Sperren in den verschiedenen Isolationlevel wird durch die folgende Tabelle erklärt: Isolationlevel Write-Operation Read-Operation Range-Operation READ UNCOMMITTED S S S READ COMMITTED T S S REPEATABLE READ T T S SERIALIZABLE T T T S: Sperre wird unmittelbar vor dem Statement gesetzt und unmittelbar danach gelöst! T: Sperre wird zu Beginn der Transaktion gesetzt und mit dem Ende der Transaktion (commit, rollback) gelöst! 17
Definition eines Sicherheitslevels für eine Transaktion (Standard SQL-99): SET TRANSACTION [<access mode>] [<isolation-level>] Mit: <access mode>:= READ ONLY READ WRITE <isolation-level>:= ISOLATION LEVEL <isolation> <isolation>:= READ UNCOMMITTED READ COMMITTED REPEATABLE READ SERIALIZABLE 18
Zum automatischen Setzen von Sperren durch das DBMS sind besondere Regeln implementiert, die Sperrprotokolle. Es gibt verschiedene Sperrprotokolle, die sich auch wieder darin unterscheiden, was sie alles zulassen an Problemen bzw. ausschliessen! Zur Einhaltung der Isolation-Bedingung wird heute zumeist das 2-Phasen-Sperrprotokoll eingesetzt. Dieses ist wie folgt definiert: Phase 1: Phase 2: Jede Transaktion setzt die Sperren, die sie setzen kann und beginnt die von ihr gesperrten Datenobjekte zu bearbeiten. Sobald eine Transaktion ihre erste Sperre löst, darf sie keine neuen Sperren mehr setzen! Lediglich die bereits gesperrten Objekte werden weiter verarbeitet und die gesetzten Sperren nach und nach gelöst. 19
Ist also eine Menge von Transaktionen gegeben, die parallel auf den gleichen Datenbestand zugreifen, so kann man beweisen: Theorem: Gehorchen alle Transaktionen eines Datenbanksystems dem 2-Phasen- Sperrprotokoll, so ist jede Ausführung jeder Menge parallel arbeitender Transaktionen serialisierbar Serialisierbarkeit beinhaltet die Lösung des Isolation-Problems: Definition: Die Ausführung einer Menge paralleler Transaktionen ist serialisierbar, falls das gleiche Ergebnis erzielt werden kann durch Hintereinanderausführung der einzelnen Transaktionen 20
Die Ausführung einer Menge parallel arbeitender Transaktionen wird vom Transaktionsmanager des DBMS in sogenannten Ablaufplänen, schedules, organisiert. Sind also die schedules eines Datenbanksystems nach dem 2-Phasen- Sperrprotokoll organisiert, kann nach dem Ergebnis der vorigen Folie kein Isolation-Problem auftreten! Allerdings bedeutet das Setzen von Sperren auf jeden Fall, dass andere Transaktionen warten müssen. Wünschenswert wäre es also, schedules erstellen zu können, die auch das Isolation-Problem lösen, ohne Sperren benutzen zu müssen. Dieses theoretische Problem wird im Anschluss an die folgenden Überlegungen behandelt. Das Setzen von Sperren verursacht ein neues Problem, sogenannte deadlocks. 21
Das Instrumentarium der Sperren schafft ein neues Problem: deadlocks Beispiel: T1 Zeit T2 Begin T1 1 rlock1(x) 2 r1(x) 3 4 Begin T2 5 rlock2(y) 6 r2(y) wlock1(y)?? 7 8 wlock2(x)?? T1 und T2 warten jeweils auf die Aufhebung der Lesesperre, um ihre Schreibsperre setzen zu können! 22
Zur Lösung des deadlock-problems gibt es 2 prinzipielle Möglichkeiten: a) Einsatz von Strategien zur Erkennung und Beseitigung von deadlocks b) Einsatz spezieller Sperrprotokolle, die deadlocks verhindern Zu a) Erkennung von deadlocks mittels Wartegraphen: T1 T2 T3 T4 T5 Jeder Zykel in einem Wartegraph entspricht einem deadlock. Zykel in Graphen können durch effiziente Algorithmen erkannt werden. deadlocks werden dann aufgelöst dadurch, dass gewisse beteiligte Transaktionen (oder alle) zurückgerollt und zeitversetzt neu gestartet werden. 23
Man kann dem DBMS (Transaktionsmanager) gewisse Regeln vorgeben, nach denen Transaktionen für den Abbruch ausgewählt werden, die an einem deadlock beteiligt sind. Mögliche Kriterien sind z. B.: Anzahl der aufgebrochenen Zykel Länge einer Transaktion Rücksetzaufwand einer Transaktion. (es gibt weitere Kriterien) 24
Zu b) prinizielle Verhinderung von deadlocks: Man kann das Auftreten von deadlocks verhindern durch den Einsatz spezieller Sperrprotokolle: Konservative Sperrprotokolle verhindern das Auftreten von deadlocks! Konservative Sperrprotokolle beinhalten, dass eine Transaktion alle benötigten Sperren zu Beginn ihrer Arbeit setzen muss, und erst dann zu arbeiten beginnen kann. Anmerkung: Das 2-Phasen-Sperrprotokoll ist kein konservatives Sperrprotokoll, es lässt also deadlocks zu! 25
Fazit: Das Isolation-Problem kann durch Setzen von Sperren gelöst werden Automatisches Sperren wird durch Sperrprotokolle geregelt Vermeidung aller Isolation-Probleme beinhaltet die Koppelung des Aufhebens der Sperren an die Transaktionsstatements commit und rollback Sperren verursachen ein neues Problem: deadlocks deadlocks können nur durch konservative Sperrprotokolle verhindert werden. Ansonsten müssen sie durch spezielle Strategien aufgelöst werden Sperren verursachen performance-verluste, deshalb sollte das DBMS nur serialisierbare Ablaufpläne erstellen, was aber nicht immer geht. Theoretische Konzepte zur Erstellung von serialisierbaren Ablaufplänen sind vorhanden. 26