MySQL Transaktionen – Für besonders sensitive Abläufe

Standardmäßig werden MySQL-Befehle, wie UPDATE, INSERT, oder DELETE direkt auf vom MySQL-Server ausgeführt und auf der Festplatte persistent gespeichert. Führt man zusammenhängende Operationen aus, z.B. von einem Nutzerkonto einen Betrag abbuchen, bei einem anderen Nutzer das Guthaben hinzufügen und die ganze Aktion in einer Kontobewegungs-Tabelle festhalten, so kann diese einzelne Ausführung der entsprechenden SQL-Befehle in selten Fällen zu unangenehmen Seiteneffekten führen.

Stürzt z.B. der MySQL-Server nach der ersten Operation ab, so wurde dem Kunden Guthaben abgebucht, aber es wurde weder dem Empfänger gut geschrieben noch in der Kontobewegungs-Tabelle protokolliert. Der Betrag ist einfach verschwunden. Mittels Datenbanktransaktion lässt sich dies zu Glück gut verhindern.

Ursachen für unterbrochene Script-Abläufe

Der Script-Ablauf kann durch verschiedene Ursachen unterbrochen werden. Dies kann ein Absturz, eine Fehlermeldung oder ein Verbindungsabbruch durch den MySQL-Server sein, oder aber auch ein Absturz eures Webserver. Gerne treten auch im PHP-Script Fehler auf, die dazu führen, dass das Script nur zur Hälfte ausgeführt wird. Halb ausgeführte Operationen sind besonders kritisch, wenn die Integrität der Daten absolute Priorität hat und Daten-Inkonsistenzen nicht toleriert werden können. Dies ist der Fall bei Finanztransaktionen oder bei Cryptocurrency-Anwendung wie beispielsweise der  bitqt app.

Solche halb abgebrochenen Operationen treten relativ selten auf. Dies macht es aber gerade schwierig, entsprechend kritische Stellen zu identifizieren, da die Abbrüche beim Testen dann quasi nie auftreten. Daher gilt es von Anfang an gleich ein sauberes Software-Design zu haben und zusammenhängende Datenbank-Operationen per Datenbanktransaktion abzusichern.

 

Datenbanktransaktionen in MySQL

Normalerweise werden von MySQL sämtliche Änderungen sofort dauerhaft gespeichert. Um dies auszuschalten, muss autocommit deaktiviert werden:

Anschließend können wir eine neue Transaktion starten:

Danach können wir beliebig viele SQL-Befehle ausführen, für das obige Beispiel mit der Kontobewegung:

Diese drei Befehle buchen dem Benutzer 84 einen Betrag von 100 ab und schreibt es dem Kunden 93 gut. Das ganze wird noch in einer Kontobewegungs-Tabelle protokolliert.

Führt man zwischen den UPDATE/INSERT/DELETE-Befehlen eine Datenbankabfrage durch, erhält man das aktualisierte Ergebnis zurück. Sprich, nach dem ersten Update wurden dem Benutzer 1 bereits 100 Euro abgebucht. Diese ist aber noch nicht persistent auf der Festplatte gespeichert und ihr erhaltet diesen Abfragewert nur für eure Transaktion.

Hat man seine Operationen alle durchgeführt, kann man die Transaktion wie folgt abschließen:

Mittels COMMIT werden alle Änderungen, seit Beginn der Transaktion, durchgeführt und persistent gespeichert.  Sollte die Transaktion nicht beendet werden, z.B. durch einen Absturz oder ein Programmfehler, so werden die Änderungen nicht gespeichert und die vorherigen, unveränderten Werte sind vorhanden.

Möchte man die Transaktion manuell abbrechen, und die Änderungen Rückgängig machen, so geht dies mittels:

Für weitere Details zu diesen Befehlen, siehe die MySQL Dokumentation.

Datenbanktransaktion mittels PDO

Verwendet ihr PDO um eure Datenbank-Abfragen zu senden, so existieren zum Glück einige Funktionen, die das Leben etwas vereinfachen.

Mittels beginTransaction() starten wir eine neue Transaktion. Alle nachfolgenden Befehle / Änderungen sind erst mal nur temporär, bis abschließend commit() ausgeführt wird.

Kommt es zu einem Abbruch vor dem Aufruf von commit(), so werden keine Teildaten / Teiländerungen gespeichert. Es gilt das Prinzip: Ganz oder gar nicht.

Autor:
Zurück zur Übersicht aller Beiträge