1. Transaktionen und Parallelität
Transaktionen und Parallelität
Abschnitt betitelt „Transaktionen und Parallelität“Sobald mehr als eine Person gleichzeitig mit einer Datenbank arbeitet, entsteht ein Problem, das es bei einer einzelnen Datei nicht gibt: Zwei Vorgänge greifen im selben Moment auf dieselben Daten zu und geraten sich in die Quere. Eine Überweisung bucht ab, während eine andere den Kontostand liest. Zwei Personen buchen den letzten freien Platz. Damit dabei nichts durcheinandergerät, kennt jede ernstzunehmende Datenbank das Konzept der Transaktion.
Was ist eine Transaktion?
Abschnitt betitelt „Was ist eine Transaktion?“Eine Transaktion ist eine Folge von Datenbankoperationen, die als eine Einheit behandelt wird: entweder wird alles ausgeführt oder gar nichts. Das klassische Beispiel ist eine Überweisung: Geld beim einen Konto abbuchen und beim anderen gutschreiben. Bricht der Vorgang nach dem Abbuchen ab, darf das Geld nicht einfach verschwinden.
BEGIN; UPDATE accounts SET balance = balance - 100 WHERE id = 1; UPDATE accounts SET balance = balance + 100 WHERE id = 2;COMMIT;Mit COMMIT werden die Änderungen dauerhaft. Mit ROLLBACK werden sie verworfen, als hätte die Transaktion nie stattgefunden.
Damit eine Transaktion verlässlich ist, muss sie vier Eigenschaften erfüllen, zusammengefasst im Akronym ACID:
- Atomicity (Atomarität): Alles oder nichts. Eine Transaktion wird ganz ausgeführt oder ganz verworfen.
- Consistency (Konsistenz): Die Datenbank geht von einem gültigen Zustand in den nächsten über. Regeln wie Fremdschlüssel oder Constraints bleiben erfüllt.
- Isolation: Gleichzeitig laufende Transaktionen stören sich nicht gegenseitig; das Ergebnis ist so, als liefen sie nacheinander.
- Durability (Dauerhaftigkeit): Nach einem
COMMITbleiben die Daten erhalten, auch bei einem Stromausfall unmittelbar danach.
Die vier Eigenschaften am Beispiel eines Medienarchivs
Abschnitt betitelt „Die vier Eigenschaften am Beispiel eines Medienarchivs“Als Beispiel dient das Media-Asset-Management (MAM) einer Postproduktion. Videoclips stehen in der Tabelle clips, ihre technischen Metadaten (Codec, Auflösung) in clip_meta, und eine Render-Farm arbeitet Aufträge aus render_jobs ab. An diesem System lassen sich alle vier Eigenschaften anschaulich zeigen.
Atomicity. Beim Import eines Clips müssen der Clip und seine Metadaten entstehen. Bricht der Vorgang nach dem ersten Schritt ab, darf kein Clip ohne Metadaten zurückbleiben:
BEGIN; INSERT INTO clips (clip_id, title, project_id) VALUES (501, 'Intro_4K', 12); INSERT INTO clip_meta (clip_id, codec, width, height) VALUES (501, 'H.265', 3840, 2160);COMMIT;Consistency. Nach der Transaktion sind alle Regeln der Datenbank weiter erfüllt. Über project_id (Fremdschlüssel) verweist jeder Clip auf ein existierendes Projekt, und ein Constraint CHECK (duration_s > 0) verhindert einen Clip mit null Sekunden Länge. Eine Transaktion, die das verletzen würde, wird abgewiesen.
Isolation. Zwei Cutter bearbeiten zeitgleich dieselbe Schnittliste. Dank Isolation sieht keiner die halbfertigen Änderungen des anderen; das Ergebnis ist so, als hätten sie nacheinander gearbeitet.
Durability. Bestätigt die Render-Farm einen fertigen Auftrag mit COMMIT, bleibt dieser Status erhalten, selbst wenn der Server eine Sekunde später abstürzt. Nach dem Neustart ist der Job weiterhin als fertig verzeichnet.
Das Problem der Parallelität
Abschnitt betitelt „Das Problem der Parallelität“Die schwierigste der vier Eigenschaften ist die Isolation. Laufen viele Transaktionen gleichzeitig, treten typische Fehler auf. Man fasst sie in Fehlerklassen zusammen, hier jeweils am MAM-System veranschaulicht:
- Lost Update: Zwei Vorgänge lesen denselben Wert, rechnen darauf und schreiben zurück; die zweite Änderung überschreibt die erste. Beispiel: der Aufrufzähler eines Videos. Zwei Streaming-Server lesen
views = 1000, beide erhöhen auf 1001 und speichern. Statt 1002 steht am Ende 1001 — ein Aufruf ist verloren. - Dirty Read: Eine Transaktion liest Daten, die eine andere geändert, aber noch nicht committet hat. Beispiel: Ein Veröffentlichungsdienst liest einen Render-Job als „fertig” und stellt das Video online. Dann bricht der Rendervorgang ab (Rollback) — veröffentlicht wurde ein Clip, der nie fertig gerendert wurde.
- Non-Repeatable Read: Dieselbe Zeile wird in einer Transaktion zweimal gelesen und liefert verschiedene Werte, weil dazwischen jemand committet hat. Beispiel: Eine Abrechnung liest zu Beginn die Cliplänge mit 120 s, nach einem parallelen Re-Encode am Ende 90 s — die Rechnung wird in sich widersprüchlich.
- Phantom Read: Dieselbe Abfrage liefert beim zweiten Lauf zusätzliche Zeilen. Beispiel: Ein Report zählt „alle 4K-Clips im Projekt”. Während er läuft, lädt ein Kollege drei neue 4K-Clips hoch; der zweite Zähllauf liefert plötzlich mehr.
Der Lost Update lässt sich schon ohne hohe Isolationsstufe vermeiden, indem man die Datenbank rechnen lässt, statt in der Anwendung mit einem veralteten Wert zurückzuschreiben:
-- Vulnerable: read first, then write back the stale valueSELECT views FROM clips WHERE clip_id = 501; -- reads 1000UPDATE clips SET views = 1001 WHERE clip_id = 501;
-- Safe: the database increments atomically, without fetching the old value into the appUPDATE clips SET views = views + 1 WHERE clip_id = 501;Isolationsstufen
Abschnitt betitelt „Isolationsstufen“Man könnte jede Transaktion streng nacheinander ausführen, dann gäbe es keine dieser Fehler. Das wäre aber langsam. Deshalb bietet SQL vier Isolationsstufen, die einen Kompromiss zwischen Sicherheit und Geschwindigkeit erlauben. Je höher die Stufe, desto mehr Fehler werden verhindert, desto weniger Parallelität ist aber möglich.
| Isolationsstufe | Dirty Read | Non-Repeatable Read | Phantom Read |
|---|---|---|---|
| READ UNCOMMITTED | möglich | möglich | möglich |
| READ COMMITTED | verhindert | möglich | möglich |
| REPEATABLE READ | verhindert | verhindert | möglich |
| SERIALIZABLE | verhindert | verhindert | verhindert |
BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; -- ... queries ...COMMIT;Die Stufen an Medienbeispielen
Abschnitt betitelt „Die Stufen an Medienbeispielen“- READ UNCOMMITTED erlaubt sogar Dirty Reads. Ein Vorschaudienst könnte den halbfertigen Render-Status eines Kollegen sehen. In PostgreSQL verhält sich diese Stufe ohnehin wie READ COMMITTED; man wählt sie praktisch nie.
- READ COMMITTED zeigt nur committete Daten. Für die meisten MAM-Zugriffe — einen Clip öffnen, Metadaten anzeigen — genau richtig.
- REPEATABLE READ garantiert innerhalb einer Transaktion eine stabile Momentaufnahme. Eine Monatsabrechnung über alle Cliplängen liest durchgehend dieselben Werte, auch wenn nebenbei re-encodiert wird.
- SERIALIZABLE verhält sich, als liefen die Transaktionen streng nacheinander. Nötig etwa beim Verkauf begrenzter Streaming-Plätze für ein Live-Event: Kein Platz darf doppelt vergeben werden.
Ein Live-Event bietet 100 gleichzeitige Streams. Zwei Zuschauer lösen im selben Moment den letzten freien Platz ein:
BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; SELECT available FROM event_seats WHERE event_id = 7; -- reads 1 -- The app books only if available > 0: UPDATE event_seats SET available = available - 1 WHERE event_id = 7;COMMIT;Unter SERIALIZABLE erkennt die Datenbank den Konflikt: Eine der beiden Transaktionen wird abgewiesen und muss wiederholt werden. Beim zweiten Versuch ist available = 0, und der Zuschauer bekommt korrekt eine Absage. Ohne diese Stufe könnten beide den letzten Platz buchen — ein Lost Update, und das Event wäre überbucht.
Sperren und Deadlocks
Abschnitt betitelt „Sperren und Deadlocks“Um Isolation umzusetzen, verwenden Datenbanken Sperren (Locks). Bevor eine Transaktion eine Zeile ändert, sperrt sie diese, sodass andere warten müssen. SELECT ... FOR UPDATE fordert eine solche Sperre ausdrücklich an.
Sperren können aber zu einem Deadlock führen: Transaktion A hält Sperre 1 und wartet auf Sperre 2, während Transaktion B Sperre 2 hält und auf Sperre 1 wartet. Beide warten ewig. Datenbanken erkennen das und brechen eine der beiden Transaktionen ab, die dann wiederholt werden muss.
Vermeiden lässt sich das, indem man Sperren immer in derselben Reihenfolge anfordert und Transaktionen kurz hält.
Zusammenfassung
Abschnitt betitelt „Zusammenfassung“- Eine Transaktion ist eine Alles-oder-nichts-Einheit, gesichert durch ACID.
- Parallele Zugriffe können typische Fehler erzeugen: Lost Update, Dirty Read, Non-Repeatable Read, Phantom Read.
- Isolationsstufen wägen zwischen Sicherheit und Geschwindigkeit ab; READ COMMITTED ist der übliche Standard, SERIALIZABLE der strengste Fall.
- Sperren setzen die Isolation um, können aber zu Deadlocks führen, die die Datenbank durch Abbruch einer Transaktion auflöst.