← Datenbankadministration für Sysadmins
Transaktionen und Isolationsstufen: Garantien, Sperren und ihr Preis
Zwei Buchungen auf dasselbe Konto, beide fehlerfrei, beide bestätigt — und am Ende fehlt ein Betrag. Keine Datenbank hat dabei etwas falsch gemacht. Dieses Modul benennt die fünf Nebenläufigkeitsfehler, zeigt, welche Isolationsstufe welchen davon ausschließt, und beendet den häufigsten Irrtum im Datenbankbetrieb: dass eine niedrigere Stufe blockierende Schreibvorgänge löst.
Lehrtext · 10 Abschnitte · zuletzt geprüft: 2026-09-12
Fünf Fehler, die einen Namen haben
Sobald zwei Transaktionen gleichzeitig auf dieselben Daten zugreifen, können Ergebnisse entstehen, die bei einzelner Ausführung unmöglich wären. Diese Effekte heißen Anomalien, und sie haben feste Namen — wer sie benennen kann, kann die richtige Stufe wählen, statt sie zu raten.
Dirty Read — Eine Transaktion liest eine Änderung, die eine andere noch nicht bestätigt hat. Wird die andere zurückgerollt, hat man einen Wert gelesen, den es nie gab.
Non-Repeatable Read — Dieselbe Zeile wird innerhalb einer Transaktion zweimal gelesen und liefert zwei verschiedene Werte, weil dazwischen jemand anderes bestätigt hat.
Phantom Read — Dieselbe Abfrage wird zweimal ausgeführt und liefert beim zweiten Mal zusätzliche Zeilen, weil jemand anderes passende Zeilen eingefügt hat.
Serialisierungsanomalie — Mehrere Transaktionen werden erfolgreich bestätigt, und das Gesamtergebnis passt zu keiner Reihenfolge, in der man sie nacheinander hätte ausführen können.
Lost Update — Zwei Transaktionen lesen denselben Wert, rechnen beide damit und schreiben beide zurück. Die zweite überschreibt die erste, ohne sie gesehen zu haben.
Die Stufen und was sie versprechen
Der SQL-Standard beschreibt vier Stufen. Er legt dabei fest, welche Anomalien auf einer Stufe nicht auftreten dürfen — nicht, welche auftreten müssen. Ein System darf also strenger sein als gefordert, und genau das nutzen beide Systeme aus.
READ UNCOMMITTED- Schwächste Stufe. Dirty Reads erlaubt.
READ COMMITTED- Keine Dirty Reads. Non-Repeatable Reads und Phantome möglich. Voreinstellung in beiden Systemen.
REPEATABLE READ- Zusätzlich keine Non-Repeatable Reads. Ob Phantome möglich sind, unterscheidet die beiden Systeme — siehe unten.
SERIALIZABLE- Strengste Stufe. Das Ergebnis entspricht einer Ausführung nacheinander.
Die Wahl ist ein Handel: Jede Stufe nach oben kauft Verlässlichkeit und bezahlt sie mit Nebenläufigkeit, mit Wartezeit oder mit Wiederholungen. Es gibt keine Stufe, die nur Vorteile hat — und die Voreinstellung ist bewusst nicht die strengste.
PostgreSQL: vier Namen, drei Stufen
Man kann in PostgreSQL alle vier Standardstufen anfordern, aber intern sind nur drei verschiedene umgesetzt. Die Dokumentation stellt das ausdrücklich fest: Der Modus READ UNCOMMITTED verhält sich wie READ COMMITTED, weil das die einzig sinnvolle Abbildung der Standardstufen auf die Mehrversionen-Architektur ist.
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED wird angenommen und ändert nichts. Wer es setzt, um „schneller zu lesen“, bekommt exakt das Verhalten von vorher — nur steht jetzt eine Zeile im Code, die eine Absicht behauptet, die das System nicht umsetzt. Dirty Reads sind in PostgreSQL gar nicht erreichbar.Die zweite Abweichung geht in die andere Richtung. Die Dokumentation hält fest, dass PostgreSQLs Umsetzung von REPEATABLE READ keine Phantom Reads zulässt — strenger, als der Standard es verlangt, und laut Standard zulässig, weil höhere Garantien erlaubt sind. Umgesetzt ist die Stufe als das, was in der Literatur Snapshot Isolation heißt.
Auf der Voreinstellung READ COMMITTED sieht eine Abfrage laut Dokumentation einen Schnappschuss zum Zeitpunkt, an dem die Abfrage zu laufen beginnt — nicht die Transaktion. Daraus folgt unmittelbar: Zwei aufeinanderfolgende SELECT-Befehle innerhalb einer Transaktion können verschiedene Daten sehen, wenn dazwischen jemand bestätigt hat. Wer einen Bericht aus mehreren Abfragen zusammensetzt, bekommt auf dieser Stufe kein zusammenhängendes Bild.
Kurzcheck
Ein Auswertungsjob liest in einer Transaktion erst eine Summe aus der Kopftabelle und danach die Einzelposten. Die beiden passen gelegentlich nicht zusammen. Welche Stufe behebt das?
REPEATABLE READ— alle Abfragen sehen denselben SchnappschussREAD UNCOMMITTED— dann sieht der Job auch die laufenden Änderungen- Keine — das ist ein Fehler in der Abfrage und gehört dort behoben
Treffer. Richtig. Ab dieser Stufe liegt der Schnappschuss auf dem Beginn der Transaktion statt auf dem Beginn jeder einzelnen Abfrage, und alle Lesevorgänge sehen denselben Stand.
SQL Server: derselbe Stufenname, zwei Verhalten
Bei SQL Server ist READ COMMITTED ebenfalls die Voreinstellung — aber was diese Stufe tut, hängt an einer Datenbankeinstellung. Die Dokumentation beschreibt beide Fälle getrennt.
READ_COMMITTED_SNAPSHOT=OFF- Die Engine nimmt gemeinsame Sperren, um andere Transaktionen am Ändern gelesener Zeilen zu hindern. Lesevorgänge können auf Schreiber warten. Voreinstellung bei SQL Server.
READ_COMMITTED_SNAPSHOT=ON- Die Engine arbeitet mit Zeilenversionen und zeigt jeder Anweisung einen konsistenten Schnappschuss zum Anweisungsbeginn. Sperren werden dafür nicht verwendet. Voreinstellung bei Azure SQL Database.
Bei REPEATABLE READ gehen die beiden Systeme auseinander. SQL Server hält auf dieser Stufe gemeinsame Sperren auf allen gelesenen Daten bis zum Ende der Transaktion. Andere Transaktionen können deshalb keine gelesene Zeile ändern — aber sie können neue Zeilen einfügen, die zur Suchbedingung passen. Wiederholt die Transaktion ihre Abfrage, erhält sie die neuen Zeilen: Phantom Reads sind hier also möglich, in PostgreSQL nicht. Die Dokumentation weist zudem darauf hin, dass die Nebenläufigkeit dadurch geringer ist als bei READ COMMITTED, und empfiehlt die Stufe nur, wenn sie wirklich nötig ist.
Daneben kennt SQL Server eine eigene Stufe SNAPSHOT. Sie muss mit ALLOW_SNAPSHOT_ISOLATION freigeschaltet sein, fordert beim Lesen keine Sperren an und blockiert damit keine Schreiber — und wird von ihnen nicht blockiert. Eine bereits mit einer anderen Stufe begonnene Transaktion lässt sich laut Dokumentation nicht nachträglich auf SNAPSHOT umstellen; der Versuch bricht die Transaktion ab.
Der Satz, der den Mythos beendet
Die häufigste Fehlvorstellung im Datenbankbetrieb lautet: Wenn die Anwendung blockiert, nimmt man die Isolationsstufe herunter, dann löst sich das. Auf der Leseseite stimmt das teilweise. Auf der Schreibseite ist es falsch, und die Dokumentation sagt das in einem Satz.
Daraus folgt: Wer zwei schreibende Transaktionen auf derselben Zeile hat, löst das Warten durch keine Stufe der Welt. Isolationsstufen regeln, wie stark ein Leser vor den Änderungen anderer geschützt wird. Sie regeln nicht, wie lange ein Schreiber seine Sperre hält — das regelt allein die Dauer seiner Transaktion.
Das gilt auch für den bekanntesten Vertreter dieser Idee. READ UNCOMMITTED hat laut Dokumentation dieselbe Wirkung, als würde man NOLOCK auf alle Tabellen in allen SELECT-Anweisungen einer Transaktion setzen. Was man dafür bekommt, steht im selben Abschnitt: Es lassen sich unbestätigte Änderungen lesen, Werte können sich ändern und Zeilen können im Ergebnis auftauchen oder verschwinden, bevor die Transaktion endet.
READ_COMMITTED_SNAPSHOT ON oder die SNAPSHOT-Stufe. Sie ist nicht kostenlos: Die alten Zeilenversionen müssen irgendwo liegen, und das geht bei SQL Server zulasten von tempdb. Die Umstellung selbst ist ebenfalls keine Kleinigkeit — beim Setzen von READ_COMMITTED_SNAPSHOT darf laut Dokumentation keine andere Verbindung in der Datenbank offen sein.Lost Update: der Fehler, den keine Voreinstellung verhindert
Der teuerste Nebenläufigkeitsfehler steht in keiner Anomalien-Tabelle, weil er kein Lesefehler ist, sondern ein Muster: lesen, im Anwendungscode rechnen, zurückschreiben.
Zwei Buchungen, ein verlorener Betrag
Szenario
Zwei Sitzungen buchen gleichzeitig auf dasselbe Konto. Beide arbeiten auf der Voreinstellung READ COMMITTED.
Anforderungen
- Beide lesen den Kontostand in die Anwendung
- Beide rechnen dort einen Betrag hinzu
- Beide schreiben das Ergebnis mit einem vollständigen Wert zurück
Schritte
- Sitzung A liest den Stand 1.000 und rechnet +100.
- Sitzung B liest — ebenfalls 1.000, denn A hat noch nichts geschrieben — und rechnet +50.
- A schreibt 1.100 und bestätigt. B schreibt 1.050 und bestätigt.
- Ergebnis: 1.050. Die Buchung von A ist verschwunden, obwohl beide Transaktionen fehlerfrei durchgelaufen sind und beide Erfolg gemeldet haben.
Merksatz: Kein System hat hier einen Fehler gemacht. Beide Transaktionen waren in sich korrekt — der Fehler liegt darin, dass zwischen Lesen und Schreiben eine Rechnung außerhalb der Datenbank stattfand.
Es gibt drei Auswege, und sie kosten Verschiedenes.
- Im Befehl rechnen
- Statt einen fertigen Wert zu schreiben, die Änderung relativ ausdrücken. Die Engine liest und schreibt dann in einem Schritt, und die exklusive Sperre auf der Zeile deckt beides ab. Billigste Lösung, aber nur für einfache Rechnungen.
- Zeile beim Lesen sperren
SELECT ... FOR UPDATEsperrt die gelesenen Zeilen so, als würden sie geändert. Die zweite Sitzung wartet. Funktioniert auch bei komplexer Rechnung — kostet Wartezeit und erhöht die Deadlock-Gefahr.- Höher stufen und wiederholen
- Ab
REPEATABLE READbricht die zweite Transaktion mit einem Serialisierungsfehler ab, statt zu überschreiben. Sauberste Trennung — verlangt aber, dass die Anwendung wiederholen kann.
Wer höher stuft, muss wiederholen können
Die höheren Stufen sind kein Schalter, den man allein im Betrieb umlegt. Die Dokumentation formuliert die Bedingung unmissverständlich: Anwendungen, die diese Stufe verwenden, müssen darauf vorbereitet sein, Transaktionen wegen Serialisierungsfehlern zu wiederholen.
Praktisch heißt das: Die Anwendung muss den Fehler erkennen, die gesamte Transaktion von vorn beginnen und das eine begrenzte Zahl von Malen tun. Beim zweiten Durchlauf sieht sie die zwischenzeitlich bestätigte Änderung als Teil ihres Ausgangsbildes, sodass kein logischer Konflikt mehr besteht. Erkennen lässt sich der Fall zuverlässig über den SQLSTATE-Wert 40001, den Serialisierungsfehler immer zurückgeben.
REPEATABLE READ gestellt werden, ohne dass jemand eine Wiederholungslogik bauen muss. Genau das ist der billigste sinnvolle Einsatz der höheren Stufe.SERIALIZABLE geht darüber hinaus und überwacht zusätzlich Bedingungen, unter denen ein Satz gleichzeitiger Transaktionen zu einem Ergebnis führen würde, das zu keiner Reihenfolge nacheinander passt. PostgreSQL verwendet dazu Prädikatsperren, die im Systemkatalog pg_locks als SIReadLock auftauchen. Die Dokumentation hält eine wichtige Eigenschaft fest: Diese Sperren blockieren nicht und können deshalb an keinem Deadlock beteiligt sein. Bezahlt wird stattdessen mit dem Aufwand der Überwachung und mit den Wiederholungen.
SERIALIZABLE verhindert Anomalien, aber nicht jede Fehlermeldung, die bei echter Ausführung nacheinander nicht aufträte. Die Dokumentation nennt den Fall ausdrücklich: Verletzungen einer Eindeutigkeitsbedingung können auch dann auftreten, wenn zuvor geprüft wurde, dass der Schlüssel noch nicht vorhanden ist.Sperren: was wirklich blockiert — und wie lange
Unter den Stufen liegt der Sperrmechanismus, und dort gibt es zwei Missverständnisse, die beide aus den Namen stammen.
ROW enthält — die Namen sind historisch gewachsen. Ein ROW EXCLUSIVE sperrt nicht eine Zeile, sondern die Tabelle in einem bestimmten Modus. Der einzige tatsächliche Unterschied zwischen den Modi ist, mit welchen anderen Modi sie in Konflikt stehen.Das zweite Missverständnis betrifft die Leser. Zeilensperren beeinträchtigen das Abfragen von Daten laut Dokumentation nicht; sie blockieren ausschließlich Schreiber und andere Sperrende auf derselben Zeile. Ein SELECT bleibt also in PostgreSQL nicht an einem laufenden UPDATE hängen — was erklärt, warum NOLOCK-Denken aus der SQL-Server-Welt hier von vornherein keinen Gegenstand hat.
Die operativ wichtigste Aussage betrifft aber die Zeit. Solange kein Deadlock erkannt wird, wartet eine Transaktion, die eine Sperre sucht, laut Dokumentation unbegrenzt darauf, dass die konfliktierende Sperre freigegeben wird. Es gibt keine Voreinstellung, die das nach einer Weile abbricht.
Deadlock: erkannt, aufgelöst, nicht vorhersagbar
Ein Deadlock ist der Fall, in dem zwei Transaktionen jeweils eine Sperre halten, die die andere braucht. Ohne Eingriff würden beide unbegrenzt warten — siehe oben.
PostgreSQL erkennt solche Situationen laut Dokumentation automatisch und löst sie auf, indem es eine der beteiligten Transaktionen abbricht, sodass die andere durchlaufen kann. Und dann folgt der Satz, der für den Betrieb zählt: Welche Transaktion abgebrochen wird, ist schwer vorherzusagen und sollte nicht vorausgesetzt werden.
Wichtig ist auch, dass Deadlocks kein Sonderfall expliziter Sperrbefehle sind. Die Dokumentation zeigt das Gegenteil an einem Beispiel aus zwei ganz gewöhnlichen UPDATE-Anweisungen: Die erste Transaktion ändert Zeile A und dann Zeile B, die zweite Zeile B und dann Zeile A. Keine der beiden hat je einen Sperrbefehl ausgeführt, und trotzdem steht der Verbund.
Genau daraus ergibt sich die Abwehr. Die beste Verteidigung ist laut Dokumentation, Deadlocks zu vermeiden, indem alle Anwendungen Sperren auf mehreren Objekten in einer einheitlichen Reihenfolge anfordern. Hätten im Beispiel beide Transaktionen die Zeilen in derselben Reihenfolge bearbeitet, wäre kein Deadlock entstanden. Ergänzend nennt die Dokumentation, den ersten Zugriff auf ein Objekt gleich im strengsten später benötigten Modus zu nehmen — und, wo sich das vorab nicht sicherstellen lässt, abgebrochene Transaktionen zu wiederholen.
Die Reihenfolge, die das zusammenhält
Schritt zwei ist der, der am meisten Arbeit spart. Blockieren zwei Schreiber einander, hilft keine Stufe — eine Transaktion erhält immer eine exklusive Sperre auf dem, was sie ändert, und hält sie bis zum Ende. Die einzige wirksame Stellschraube ist dann, wie lange diese Transaktion offen bleibt.
serial-Spalte — sofort für alle anderen Transaktionen sichtbar sind und nicht zurückgerollt werden, wenn die ändernde Transaktion abbricht. Ein zurückgerolltes INSERT verbraucht seine Nummer trotzdem. Lücken in einer laufenden Nummer sind deshalb normal und kein Hinweis auf verlorene Daten — wer sie als Lückenlosigkeitszusage an die Fachlichkeit verkauft, verspricht etwas, das die Datenbank nie zugesagt hat.Jetzt anwenden
Diesen Stoff gibt es als Modul mit bewerteten Entscheidungs-Checks — dieselbe Einführung, danach die Übungen.
Zum Modul →Quellen & Aktualität6 Primärquellen · zuletzt geprüft:
- 01postgresql.org/docs/current/transaction-iso.html
- 02postgresql.org/docs/current/explicit-locking.html
- 03postgresql.org/docs/current/sql-begin.html
- 04postgresql.org/docs/current/tutorial-transactions.html
- 05learn.microsoft.com/en-us/sql/t-sql/statements…n-level-transact-sql
- 06learn.microsoft.com/en-us/sql/t-sql/statements…t-abort-transact-sql