Menu

SQLite Savepoints: Verschachtelte Transaktionen

Wie Savepoints in SQLite funktionieren – benannte Marker innerhalb einer Transaktion, zu denen du zurückrollen kannst, ohne gleich alles zu verwerfen.

Diese Seite enthält ausführbare Editoren — bearbeiten, ausführen und Ausgabe sofort sehen.

Ein Savepoint ist ein benannter Lesezeichen innerhalb einer Transaktion

Eine klassische Transaktion funktioniert nach dem Alles-oder-nichts-Prinzip: Was zwischen BEGIN und COMMIT passiert, wird entweder komplett übernommen oder komplett verworfen. Meistens ist genau das gewünscht – aber manchmal hättest du es gerne feinkörniger. So nach dem Motto: „Probier diesen Block an Änderungen aus; wenn etwas schiefgeht, mach nur diesen Block rückgängig, aber lass den Rest der Transaktion weiterlaufen."

Genau dafür gibt es den SQLite Savepoint. Du setzt ein benanntes Lesezeichen, machst deine Arbeit und entscheidest dann: entweder behalten (RELEASE) oder bis zum Lesezeichen zurückspulen (ROLLBACK TO).

Adas Abbuchung und Boris' Gutschrift bleiben erhalten. Nur das fehlerhafte Update auf Nobody wurde zurückgerollt – der Rest der Transaktion bleibt unangetastet.

Die drei Befehle

Mehr als drei Anweisungen brauchst du nicht:

  • SAVEPOINT name – setzt ein Lesezeichen.
  • RELEASE SAVEPOINT name – behält alle Änderungen seit dem Lesezeichen und entfernt es.
  • ROLLBACK TO SAVEPOINT name – macht alles seit dem Lesezeichen rückgängig; das Lesezeichen selbst bleibt aber bestehen, sodass du einen neuen Versuch starten kannst.

Das Schlüsselwort SAVEPOINT hinter RELEASE und ROLLBACK TO ist übrigens optional – RELEASE risky und ROLLBACK TO risky funktionieren genauso.

Die Zeile Schritt 2 Versuch hat aus Sicht der finalen Datenbank nie existiert. Alles andere wird übernommen.

Savepoints ohne äußere Transaktion

Jetzt kommt ein kleiner Kniff: Du kannst SAVEPOINT auch ohne vorheriges BEGIN absetzen. SQLite öffnet dann im Hintergrund still und leise eine Transaktion für dich, und der äußerste Savepoint übernimmt die Rolle der Transaktion selbst. Ein RELEASE auf diesen Savepoint committet, ein ROLLBACK TO spult zurück, ohne zu committen.

Deshalb spricht man bei Savepoints manchmal auch von „benannten Transaktionen". In der Praxis solltest du die beiden Stile aber nicht mischen – das wird schnell unübersichtlich. Üblich ist: außen ein explizites BEGIN ... COMMIT als Klammer, und Savepoints nur innen für gezielte Teil-Rollbacks.

Verschachtelte Transaktionen mit Savepoints

Savepoints lassen sich stapeln. Du kannst also einen Savepoint innerhalb eines anderen setzen und den inneren zurückrollen, ohne den äußeren anzufassen:

Endstand der Tabelle: a, b, d. Das Rollback auf inner hat zwar c entfernt, aber alles, was vor inner passiert ist (also das Einfügen von b), bleibt erhalten — und die Transaktion läuft munter weiter.

Ein Rollback auf einen äußeren Savepoint verwirft auch sämtliche Änderungen der inneren Ebenen — der komplette Stack oberhalb dieses Namens wird auf einen Schlag abgewickelt:

Sowohl b als auch c sind weg. ROLLBACK TO outer macht alles rückgängig, was seit dem Setzen von outer passiert ist – inklusive inner und dem Einfügen von c.

Wann sind SAVEPOINTs in SQLite sinnvoll?

Der Klassiker: Du verarbeitest einen Batch, bei dem einzelne Einträge fehlschlagen dürfen, ohne dass dadurch der gesamte Batch verloren geht. Pack jedes Element in einen eigenen Savepoint – schlägt einer fehl, rollst du auf den Savepoint zurück und machst mit dem nächsten weiter:

In echtem Anwendungscode löst das fehlerhafte INSERT eine Exception aus, die Anwendung fängt sie ab, setzt ein ROLLBACK TO ab und macht weiter. Die zwei guten Zeilen landen in der Tabelle, die schlechte Zeile vergiftet den Batch nicht.

Genau nach diesem Muster setzen ORMs und Migrationstools übrigens verschachtelte Transaktionen in SQLite um – sie verschachteln nicht wirklich BEGIN-Blöcke (das erlaubt SQLite gar nicht), sondern bilden verschachtelte Aufrufe auf Savepoints ab.

Worauf du achten solltest

Ein paar Details, über die Einsteiger bei Savepoints regelmäßig stolpern:

  • COMMIT committet immer die gesamte Transaktion. Egal, wie viele Savepoints offen sind – COMMIT (bzw. der Alias END) schließt die komplette äußere Transaktion ab. Sieh RELEASE also nicht als Teil-Commit: Nichts ist dauerhaft gespeichert, solange die umgebende Transaktion noch nicht committet wurde.
  • ROLLBACK (ohne TO) verwirft alles. Es beendet die Transaktion und löscht sämtliche offenen Savepoints. Wenn du die Transaktion am Leben halten willst, nutze ROLLBACK TO name.
  • Ein Savepoint bleibt offen, bis er released oder durchgerollt wird. Ein vergessenes RELEASE führt nicht zu Datenverlust – das Lesezeichen liegt einfach bis zum Ende der Transaktion herum.
  • Namen müssen nicht eindeutig sein. Setzt du zweimal SAVEPOINT s, springt ROLLBACK TO s zum jüngeren der beiden. Praktisch bei Rekursion, verwirrend bei Versehen.

Als Nächstes: Views

Savepoints geben dir feinere Kontrolle über Schreibvorgänge. Im nächsten Schritt geht es darum, das Lesen zu gestalten – also eine Abfrage als benanntes, wiederverwendbares Objekt zu speichern, aus dem du wie aus einer Tabelle SELECTen kannst. Das ist ein View, und genau den schauen wir uns als Nächstes an.

Häufig gestellte Fragen

Was ist ein Savepoint in SQLite?

Ein Savepoint ist ein benannter Marker, den du innerhalb einer Transaktion setzt. Später kannst du mit ROLLBACK TO zu diesem Namen zurückspringen und alles rückgängig machen, was danach passiert ist – oder ihn mit RELEASE schließen, um die Änderungen zu behalten und den Marker zu entfernen. So lassen sich Teile einer Transaktion als kleinere, einzeln zurücknehmbare Einheiten behandeln.

Was ist der Unterschied zwischen einem Savepoint und einer Transaktion in SQLite?

Eine Transaktion startest du mit BEGIN und beendest sie mit COMMIT oder ROLLBACK. Ein Savepoint dagegen wird innerhalb einer Transaktion mit SAVEPOINT name gesetzt und gibt dir einen Rücksprungpunkt für ein teilweises Undo. Ein Rollback auf einen Savepoint beendet die umgebende Transaktion nicht – du kannst danach ganz normal weiterarbeiten und am Ende committen.

Lassen sich Savepoints in SQLite verschachteln?

Ja. Du kannst mehrere Savepoints mit unterschiedlichen Namen stapeln, und ROLLBACK TO outer macht alles bis zu diesem Punkt rückgängig – inklusive aller darin enthaltenen inneren Savepoints. Die Namen müssen nicht mal eindeutig sein: SQLite verwendet immer den zuletzt gesetzten Savepoint mit diesem Namen, also klassisches Stack-Verhalten.

Coddy programming languages illustration

Lerne mit Coddy zu programmieren

LOS GEHT'S