Transaktionssysteme: Transaktionen


Der Begriff Transaktion stammt aus dem lateinischen und bedeutet wörtlich „Überführung“. Eine Transaktion in der Informatik ist ein kurzer, abgeschlossener Vorgang, in dessen Rahmen Daten „überführt“ werden, also in eine Datenbank hinein oder aus einer heraus gebracht werden.

Eine Transaktion setzt sich aus Verarbeitungsschritten zusammen, sogenannten Operationen. Das Besondere an diesen Operationen ist, dass sie nicht notwendigerweise nacheinander ausgeführt werden müssen, sondern unter bestimmten Bedingungen auch gleichzeitig oder sogar in vertauschter Reihenfolge abgearbeitet werden können. Bei einer Transaktion „Geldüberweisung“ wäre es beispielsweise völlig gleich, in welcher Reihenfolge Abbuchung und Einbuchung ausgeführt werden.

Statt stur eine Transaktion nach der anderen abzuarbeiten, bietet sich also die Möglichkeit, sie in ihre Einzelschritte zu zerlegen und diese Schritte umzuordnen. Auf den ersten Blick mag dies sinnlos erscheinen, wir werden jedoch später sehen, dass durch solche Umordnungen die Effizienz der Abarbeitung gesteigert werden kann, das heißt, dass mehr Daten in weniger Zeit bewegt werden können.

Es drängt sich eine Reihe von Fragen auf: Wie darf ich die Operationen einer Transaktion umordnen? Darf ich die Operationen verschiedener Transaktionen vermischen? Wie ordne ich die Operationen so an, dass die Transaktionen möglichst effizient abgearbeitet werden? Gefährde ich durch Umordnung meinen Datenbestand? Um diese Fragen zu klären ist es notwendig, den Sachverhalt theoretisch zu untersuchen.

ACID – Atomarität, Konsistenz, Isolation und Dauerhaftigkeit

Bearbeiten

Für eine theoretische Betrachtung werden einige Grundsätze benötigt, die genau festlegen, welche Bedingungen beim Umgang mit Transaktionen eingehalten werden müssen. Nach den Anfangsbuchstaben der englischen Fachbegriffe fasst man diese Grundsätze unter dem Stichwort ACID zusammen:

  • Atomarität (atomicity): Transaktionen sind untrennbar. Eine Transaktion wird entweder vollständig oder überhaupt nicht ausgeführt, ein „teilweise“ oder „ein bisschen“ gibt es nicht. Betrachtet man das Beispiel der Geldüberweisung wird sofort klar, warum: Die Abbuchung alleine würde Geld vernichten, die Einbuchung alleine Geld neu erschaffen, nur beide zusammen bilden eine finanztechnisch korrekte Überweisung. Die Atomarität wirft Fragen auf wie: Was ist, wenn das System mitten in einer Transaktion abstürzt? Antworten liefert die Theorie des Wiederanlaufs, die untersucht, wie Transaktionen rückgängig gemacht werden können.
  • Konsistenz (consistency): Vor und nach einer Transaktion müssen die Daten in einem konsistenten Zustand sein. Hier wird gefordert, dass eine Transaktion die Daten ebenso „sauber“ hinterlässt, wie sie sie vorfindet. „Konsistent“ bedeutet, dass es keine Widersprüche jedwelcher Art gibt. Dies deckt technische Widersprüche wie mehrfach vorhandene Datensätze oder redundante Datensätze mit widersprüchlichem Inhalt ebenso ab wie inhaltliche Widersprüche, beispielsweise dass in einem geschlossenen Geldkreislauf plötzlich mehr Geld existiert. Wichtig ist festzuhalten, dass der Zustand der Daten während der Ausführung einer Transaktion durchaus inkonsistent sein darf.
  • Isolation (isolation): Transaktionen dürfen sich nicht gegenseitig beeinflussen. Eine Transaktion muss stets ablaufen, als hätte sie das ganze System für sich alleine. Es darf also insbesondere nicht passieren, dass zwei Transaktionen gleichzeitig dieselben Daten bearbeiten, sich dabei gegenseitig behindern und deswegen falsche Ergebnisse liefern.
  • Dauerhaftigkeit (durability): Alle Auswirkungen einer Transaktion müssen dauerhaft gespeichert werden. Dies ist zum einen eine Grundforderung an die Datenbank selbst, die Daten zuverlässig und ausfallsicher aufzubewahren. Zum anderen richtet sich diese Bedingung an unerwartete Systemausfälle, bei denen sicher gestellt werden muss, dass die Auswirkungen der zuletzt ausgeführten Transaktionen auch wirklich erhalten bleiben.

Transaktionsabschluss – Commit und Rollback

Bearbeiten

Wurde eine Transaktion erfolgreich abgeschlossen, so wird sie mit einem sogenannten Commit („festschreiben“) beendet. Das Commit teilt dem Datenverwaltungssystem mit, dass sämtliche Änderungen der Transaktion ab jetzt gemäß der Forderung nach Dauerhaftigkeit dauerhaft in der Datenbasis festgeschrieben werden sollen.

Die Forderung nach Atomarität führt dazu, dass eine Transaktion, die nicht erfolgreich beendet werden kann, überhaupt nicht erst begonnen werden sollte. Dies ist jedoch unmöglich umsetzbar, denn es könnte erst während der Bearbeitung deutlich werden, dass ein erfolgreiches Beenden unmöglich ist. Es ist jedoch möglich, so zu tun, als sei die Transaktion niemals begonnen worden, indem alle bis dahin aufgetretenen Auswirkungen rückgängig gemacht werden.

Neben dem Commit besteht daher die Möglichkeit, eine Transaktion abzubrechen. Der Abbruch bestätigt dem Datenverwaltungssystem, dass die Transaktion ohne Erfolg beendet wurde und alle Änderungen zurückgenommen werden müssen. Das Zurücknehmen der Änderungen bezeichnet man als Rollback („zurückrollen“).

Operationsklassen – Lesen und Schreiben

Bearbeiten

Sieht man einmal davon ab, dass Transaktionen dem Datenaustausch mit einer Datenbank dienen und daher vernünftigerweise nur solche Operationen beinhalten, deren Ziel eben dieser Datenaustausch ist, gibt es keine Einschränkung, welche Art von Aktion eine Operation durchführen darf. Eine Operation könnte also beispielsweise einen Datensatz auslesen, einen neuen Datensatz hinzufügen, eine Tabelle löschen oder Datensätze sortieren oder zählen; die Möglichkeiten sind wenn überhaupt nur durch das verwendete Datenbankverwaltungssystem beschränkt.

Diese Vielfältigkeit erschwert eine geordnete Betrachtung der Operationen, denn es ist nicht offensichtlich, ob sich Operationen, die neue Datensätze anlegen, anders zueinander verhalten, als solche, die bestehende Daten auslesen. Um den Untersuchungsaufwand zu minimieren ist es daher sinnvoll, gleichartige Operationen in Operationsklassen zusammenzufassen.

Eine fruchtbringende, grundlegende Aufteilung ist die in lesende und schreibende Operationen. Ein lesender Zugriff beeinflusst die Daten nicht, sondern wertet sie nur passiv aus. Schreibende Zugriffe hingegen verändern die Datenbasis durch Hinzufügen, Ändern oder Löschen von Daten.

Es kann sinnvoll sein, weitere Klassen einzuführen, beispielsweise für Operationen, die Datensätze hinzufügen, entfernen oder zählen. Für eine elementare Betrachtung ist die Unterscheidung nach lesend und schreibend jedoch ausreichend, wenn man das Hinzufügen und Entfernen eines Datensatzes als Schreiboperation auffasst, der sämtliche Datensätze eines abgesteckten Bereichs auf einmal bearbeitet.

Schreibweise

Bearbeiten

Im weiteren Verlauf wird folgende Schreibweise verwendet:

  • begin und end werden vernachlässigt
  • c steht für Commit, a für Abort, r für Read und w für Write
  • Transaktionsnamen oder -nummern werden als Index hinter den Operation angegeben: c1
  • Datensätze, auf die zugegriffen wird, werden den Operationen in Klammern nachgestellt: r1(x)
  • Operationen, die nacheinander ausgeführt werden, werden mit Komma aneinander gereiht: r1(x), w2(y)

Lost Update, Dirty Read, Non-Repeatable Read

Bearbeiten

Es gibt drei grundlegende Probleme, die bei Nebenläufigkeit auftreten können. Alle drei können bereits auftreten, wenn nur zwei Transaktionen gleichzeitig nebeneinander laufen:

  • Lost Update („verlorene Änderung“). Transaktion A schreibt einen Wert in X und läuft danach weiter. Transaktion B schreibt einen Wert in X und läuft danach weiter. Der Fehler ist, dass die Änderung der ersten Transaktion durch die Änderung der zweiten überschrieben wird. Hier liegt ein Verstoß gegen das Prinzip der Dauerhaftigkeit vor, denn die Auswirkung der ersten Transaktion geht bereits verloren, bevor sie festgeschrieben wurde. Typische Fehlersituation:
w1(x), w2(x), c1, c2
  • Dirty Read („schmutziges Lesen“). Transaktion A schreibt einen Wert in X und läuft danach weiter. Transaktion B liest den Wert von X und wird mit Commit beendet. Transaktion A wird abgebrochen. Das Problem ist, dass die zweite Transaktion einen Wert liest, der noch nicht durch ein abschließendes Commit bestätigt wurde. Wird die erste Transaktion nachträglich abgebrochen, wird der Wert verworfen und die zweite Transaktion würde mit einem falschen Wert weiter arbeiten. Hier liegt ein Verstoß gegen das Prinzip der Isolation vor, denn die Transaktionen beeinflussen sich gegenseitig. Typische Fehlersituation:
w1(x), r2(x), c2, a1
  • Non-Repeatable Read („nicht wiederholbares Lesen“). Transaktion A liest den Wert von X. Transaktion B schreibt einen Wert in X. Transaktion A liest den Wert von X. Der Fehler ist, dass die erste Transaktion nichts weiter tut, als zweimal den selben Datensatz zu lesen, aber zwei verschiedene Werte erhält. Hier liegt wiederum ein Verstoß gegen das Prinzip der Isolation vor, denn die Transaktionen beeinflussen sich gegenseitig. Typische Fehlersituation:
r1(x), w2(x), r1(x)

Mitunter wird in der Literatur ein viertes Problem aufgeführt, das eigentlich ein Spezialfall des Non-Repeatable Read ist: Das Phantomproblem. Beim Phantomproblem geht es nicht direkt um das Lesen eines unbestätigten Wertes, sondern um das Zählen einer unbestätigten Anzahl an Datensätzen. Transaktion A zählt die Anzahl der Datensätze. Transaktion B fügt Datensätze hinzu oder entfernt welche. Transaktion A zählt erneut die Anzahl der Datensätze. Die erste Transaktion erhält also zwei verschiedene Ergebnisse beim Zählen der Datensätze, was einen Verstoß gegen das Prinzip der Isolation nahe legt. Von Phantomen spricht man, weil hier Datensätze wie von Zauberhand auftauchen und verschwinden.