- das ACID-Prinzip von Transaktionen erklären
- typische Anomalien bei gleichzeitigen Transaktionen kennen
- Isolationsstufen und ihre Abwägungen einordnen
- Transaktionen im Anwendungscode richtig einsetzen und Migrationen sicher durchführen
Im vorigen Modul haben Sie gesehen, wie zwei gleichzeitige Buchungen einen Kurs überbuchen können. Die Lösung lag in der Datenbank. Diese Lektion schaut genauer hin: Was garantiert eine Transaktion eigentlich, welche Fehler können trotzdem auftreten, und wie wählt man die richtige Isolationsstufe? Das klingt nach Datenbanktheorie, entscheidet aber im Alltag darüber, ob ein Onlineshop zu viel verkauft, ob Kontostände stimmen und ob Nutzer doppelte Rechnungen bekommen.
1. Was eine Transaktion garantiert
Die Atomarität ist die bekannteste Eigenschaft: Wenn eine Bestellung angelegt, der Lagerbestand verringert und eine Zahlung vermerkt werden soll, geschieht entweder alles oder nichts. Bricht der Vorgang in der Mitte ab, rollt die Datenbank alle Änderungen zurück. Die Dauerhaftigkeit garantiert, dass eine bestätigte Transaktion auch einen Stromausfall übersteht, weil die Datenbank sie vor der Bestätigung in ein Protokoll schreibt. Die Konsistenz bedeutet, dass die definierten Regeln – eindeutige Werte, Fremdschlüssel, Prüfbedingungen – nach jeder Transaktion erfüllt sind. Die schwierigste Eigenschaft ist die Isolation.
2. Die Anomalien
Vollständige Isolation würde bedeuten, dass sich gleichzeitige Transaktionen so verhalten, als liefen sie strikt nacheinander. Das ist teuer, deshalb bieten Datenbanken abgestufte Isolationsstufen an, die bestimmte Anomalien zulassen. Man sollte sie kennen, um zu wissen, wogegen man sich schützen muss.
| Anomalie | Was passiert | Beispiel |
|---|---|---|
| Dirty Read | Lesen unbestätigter Änderungen einer anderen Transaktion | Anzeige eines Preises, der wieder zurückgenommen wird |
| Nicht wiederholbares Lesen | derselbe Wert wird zweimal gelesen und ist verschieden | Rechnung und Summe weichen ab |
| Phantom | eine Abfrage liefert beim zweiten Mal neue Zeilen | Zählung freier Plätze ändert sich während der Buchung |
| Lost Update | zwei Transaktionen überschreiben sich | letzter Kursplatz zweimal vergeben |
| Write Skew | zwei Transaktionen prüfen dieselbe Bedingung und ändern verschiedene Zeilen | zwei Ärzte tragen sich gleichzeitig aus dem Bereitschaftsdienst aus – keiner bleibt |
Wählen Sie eine Isolationsstufe und sehen Sie, wogegen sie schützt:
Verhalten von PostgreSQL. Andere Datenbanken setzen dieselben Stufen teils anders um.
3. Die richtige Stufe wählen
PostgreSQL nutzt standardmäßig Read Committed. Diese Stufe ist schnell und für viele Anwendungsfälle ausreichend, schützt aber nicht vor Lost Updates und Write Skew. Das ist kein Grund, alles auf Serializable umzustellen, denn die stärkste Stufe führt unter Last zu mehr Abbrüchen, die die Anwendung wiederholen muss. Der bessere Weg ist meist, die kritischen Stellen gezielt abzusichern.
| Muster | Umsetzung | Wofür |
|---|---|---|
| Atomare Aktualisierung | UPDATE … SET frei = frei - 1 WHERE id = … AND frei > 0 | Zähler, Bestände, Plätze |
| Zeilensperre | SELECT … FOR UPDATE innerhalb der Transaktion | Lesen, prüfen, ändern derselben Zeile |
| Eindeutige Regel | UNIQUE (mitarbeiter_id, zeitfenster) | Doppelbuchungen, doppelte Zahlungen |
| Optimistische Sperre | Versionsnummer prüfen: UPDATE … WHERE version = 7 | Bearbeitung von Formularen durch mehrere Personen |
| Serializable gezielt | nur für einzelne, komplexe Transaktionen | Write-Skew-Fälle |
4. Transaktionen im Anwendungscode
In der Praxis entstehen die meisten Probleme nicht durch falsche Isolationsstufen, sondern durch falsch gezogene Transaktionsgrenzen. Ein häufiges Muster: Die Anwendung liest einen Wert, entscheidet im Code, schreibt dann – aber in drei getrennten Datenbankaufrufen ohne gemeinsame Transaktion. Unter Last entsteht genau das Lost Update aus dem vorigen Modul. Ebenso häufig ist das Gegenteil: eine Transaktion, die viel zu viel umfasst, etwa das Hochladen einer Datei, das Erzeugen einer Vorschau und das Versenden einer E-Mail. Sie blockiert Verbindungen und Sperren über Sekunden.
Die Regel lautet: In die Transaktion gehört genau das, was gemeinsam gelingen oder scheitern muss, und nichts, was lange dauert oder außerhalb der Datenbank passiert. Für Seiteneffekte wie E-Mails oder Aufrufe externer Dienste gibt es das bereits erwähnte Outbox-Muster: Die Transaktion speichert zusätzlich einen Auftrag in einer Tabelle, und ein Hintergrundprozess führt ihn nach dem erfolgreichen Abschluss aus. So wird keine E-Mail für eine Bestellung verschickt, die nie gespeichert wurde.
5. Migrationen sicher durchführen
Zum Umgang mit Transaktionen gehört auch die Frage, wie man das Datenbankschema im laufenden Betrieb ändert. Eine neue Spalte, ein neuer Index oder eine umbenannte Tabelle kann bei großen Tabellen lange dauern und Sperren halten, die den Betrieb blockieren. Bewährt hat sich das Vorgehen in kleinen, rückwärtskompatiblen Schritten, oft „Expand and Contract“ genannt: Zuerst wird das Neue ergänzt, etwa eine neue Spalte, ohne das Alte zu entfernen. Dann schreibt die Anwendung in beide, alte Daten werden im Hintergrund übertragen. Erst wenn alles auf das Neue umgestellt ist, wird das Alte entfernt.
Einige PostgreSQL-spezifische Regeln helfen zusätzlich: Indizes auf großen Tabellen werden mit CREATE INDEX CONCURRENTLY angelegt, damit Schreibzugriffe nicht blockiert werden. Neue Spalten mit Standardwerten sind in modernen Versionen schnell, das nachträgliche Setzen von NOT NULL auf großen Tabellen dagegen nicht. Und jede Migration sollte vorab auf einer Kopie der Produktivdaten getestet werden, um ihre Dauer abzuschätzen. Wer diese Regeln beachtet, kann das Schema auch bei großen Datenmengen ohne Ausfallzeit weiterentwickeln.
Transaktionen sind damit eines der mächtigsten Werkzeuge im System Design. Sie verlagern die schwierigste Frage der Nebenläufigkeit – wer darf wann was ändern? – in eine Komponente, die seit Jahrzehnten darauf optimiert ist. Wer sie gezielt einsetzt, braucht deutlich weniger komplizierte Logik im Anwendungscode und vermeidet eine ganze Klasse schwer auffindbarer Fehler.
6. Idempotenz und Transaktionen
Eng mit Transaktionen verbunden ist die Frage, was passiert, wenn eine Anfrage wiederholt wird. Ein Nutzer klickt zweimal auf „Bezahlen“, das Netzwerk bricht nach dem Absenden ab und die App versucht es erneut, oder ein Hintergrundjob läuft nach einem Absturz ein zweites Mal. Ohne Vorkehrung entstehen doppelte Bestellungen oder Zahlungen. Die Lösung ist ein Idempotenzschlüssel: Der Client erzeugt für jeden Vorgang eine eindeutige ID und schickt sie mit. Die Datenbank speichert diese ID mit einer eindeutigen Regel zusammen mit dem Ergebnis. Kommt dieselbe ID erneut, wird kein zweiter Vorgang ausgelöst, sondern das gespeicherte Ergebnis zurückgegeben.
Das funktioniert nur zuverlässig, wenn das Speichern der ID und der eigentliche Vorgang in derselben Transaktion geschehen. Genau hier zeigt sich wieder die Stärke der Datenbank: Eine eindeutige Regel und eine Transaktion garantieren, dass derselbe Vorgang höchstens einmal wirksam wird, auch wenn tausend Anfragen gleichzeitig eintreffen. Das Modul Skalierung greift Idempotenz im Zusammenhang mit Wiederholungen und Zeitlimits noch einmal auf, denn sie ist die Voraussetzung dafür, dass automatische Wiederholungen keinen Schaden anrichten.
Zusammengefasst: Transaktionen sichern ab, dass zusammengehörige Änderungen gemeinsam gelingen, Isolationsstufen und gezielte Sperren schützen vor gleichzeitigen Zugriffen, und Idempotenzschlüssel sorgen dafür, dass Wiederholungen keinen Schaden anrichten. Wer diese drei Werkzeuge beherrscht, hat die häufigsten Datenfehler in Webanwendungen im Griff.
Testen Sie diese Fälle bewusst. Automatisierte Tests, die zwei gleichzeitige Buchungen oder eine doppelt gesendete Zahlung simulieren, decken Fehler auf, die im normalen Klicktest nie auffallen würden. Solche Tests sind mit wenig Aufwand geschrieben und bewahren vor Fehlern, die sonst erst unter echter Last im Betrieb sichtbar werden – dann, wenn sie am teuersten sind.
- [1]PostgreSQL Global Development Group (2026): Documentation – Transaction Isolation; Explicit Locking.
- [2]Berenson, H. et al. (1995): A Critique of ANSI SQL Isolation Levels. Proceedings of ACM SIGMOD, 1–10.
- [3]Kleppmann, M. (2017): Designing Data-Intensive Applications. Sebastopol: O'Reilly, Kap. 7.
- [4]Ports, D. R. K.; Grittner, K. (2012): Serializable Snapshot Isolation in PostgreSQL. Proceedings of the VLDB Endowment 5(12), 1850–1861.
Stand: September 2026. Kursmaterial der Klarwerk Akademie. Zahlen zu Latenzen und Kosten sind Größenordnungen zur Orientierung, keine Messwerte.