CodeGym /Kurse /SQL SELF /Isolationslevel SERIALIZABLE: volle Isolati...

Isolationslevel SERIALIZABLE: volle Isolation und Vermeidung von Phantom Read

SQL SELF
Level 40 , Lektion 2
Verfügbar

SERIALIZABLE ist das höchste Isolationslevel für Transaktionen in PostgreSQL. Dieses Level garantiert, dass die Ergebnisse von parallelen Transaktionen genauso sind, als ob sie SEQUENZIELL, also nacheinander, ausgeführt würden. Dabei können keine Anomalien des parallelen Ausführens (wie Dirty Read, Non-Repeatable Read, Phantom Read) auftreten.

Einfach gesagt: SERIALIZABLE sorgt für komplette Ordnung und Konsistenz zwischen parallelen Transaktionen. Das ist, als würde PostgreSQL sagen: "Alle Transaktionen – bitte in die Schlange stellen, Leute!"

Warum braucht man das Level SERIALIZABLE? Manchmal willst du einfach zu 100% sicher sein, dass deine Daten komplett konsistent bleiben, auch wenn mehrere Änderungen gleichzeitig passieren. Stell dir eine Szene im Supermarkt vor, wo mehrere Kassierer gleichzeitig Kunden bedienen. Wenn niemand auf die Reihenfolge achtet, könnten am Ende mehr Waren aus dem Laden gehen, als gekauft wurden. Mit SERIALIZABLE ist so eine Situation einfach unmöglich.

Beispiel für das Setzen des SERIALIZABLE-Levels

Um das Isolationslevel SERIALIZABLE zu setzen, benutzt du den Befehl:

SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;

Zum Beispiel, so startest du eine Transaktion mit diesem Level:

BEGIN; -- Transaktion starten
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE; -- Isolationslevel setzen
SELECT * FROM products WHERE category = 'Electronics'; -- Liste der Produkte holen
UPDATE products SET stock = stock - 1 WHERE product_id = 123; -- Bestand aktualisieren
COMMIT; -- Änderungen bestätigen

Case: Kinositzplatz-Reservierung

Schauen wir uns ein echtes Beispiel an, wo SERIALIZABLE einfach Pflicht ist. Stell dir vor, du entwickelst ein Online-Buchungssystem für Kinositze. Deine User wählen Plätze aus und du willst garantieren, dass derselbe Platz nicht von zwei Kunden gleichzeitig gekauft wird.

Erstmal erstellen wir eine Tabelle für die Sitze:

CREATE TABLE seats (
    seat_id SERIAL PRIMARY KEY,
    is_booked BOOLEAN DEFAULT FALSE
);

Jetzt fügen wir ein paar Plätze hinzu:

INSERT INTO seats (is_booked) VALUES (FALSE), (FALSE), (FALSE);

Hier ein Beispiel für eine Transaktion mit SERIALIZABLE.

So kannst du eine sichere Sitzplatzreservierung umsetzen:

BEGIN; -- Transaktion starten
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE; -- Isolationslevel SERIALIZABLE

-- Prüfen, ob der Platz frei ist
SELECT is_booked FROM seats WHERE seat_id = 1;

-- Platz reservieren
UPDATE seats SET is_booked = TRUE WHERE seat_id = 1;

COMMIT; -- Reservierung bestätigen

Wenn eine zweite parallele Transaktion versucht, denselben Platz zu reservieren, lässt PostgreSQL keine Verwirrung zu und wirft einen Fehler wegen eines Serialisierungs-Konflikts.

Vermeidung von Phantom Read

Jetzt schauen wir uns die "Phantom Reads" an, die wir unbedingt loswerden wollen. Phantom Read passiert, wenn eine Transaktion Änderungen sieht, die von einer anderen Transaktion während ihrer Laufzeit gemacht wurden. Zum Beispiel erwartet deine Transaktion eine bestimmte Anzahl von Zeilen, aber plötzlich fügt eine andere Transaktion Zeilen hinzu oder löscht welche, und das Ergebnis ändert sich.

Hier ein Beispiel:

Daten vor Start der Transaktionen

id balance user
1 1000 Alice
2 500 Bob

Transaktion 1

BEGIN;
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;

-- Zähle User mit Kontostand über 400
SELECT COUNT(*) FROM accounts WHERE balance > 400;

-- Erwartetes Ergebnis: 2 (Alice und Bob)

Transaktion 2

In einer anderen Session läuft parallel eine Transaktion:

BEGIN;
INSERT INTO accounts (id, balance, user) VALUES (3, 700, 'Charlie');
COMMIT;

Zurück zu Transaktion 1

-- Anfrage wiederholen
SELECT COUNT(*) FROM accounts WHERE balance > 400;

Jetzt, wenn du SERIALIZABLE nicht benutzt, ist das Ergebnis 3 statt 2, weil Charlie während der Arbeit von Transaktion 1 hinzugefügt wurde. Das ist genau ein Phantom Read.

Aber mit SERIALIZABLE garantiert PostgreSQL, dass Transaktion 1 Charlie nicht sieht, weil ihre "Weltsicht" beim Start der Transaktion eingefroren ist.

Besonderheiten und Einschränkungen des SERIALIZABLE-Levels

Wir haben gesehen, wie SERIALIZABLE perfekte Isolation bringt. Aber was ist schon perfekt ohne Nachteile? Lass uns ehrlich sein.

Performance-Einbußen
SERIALIZABLE braucht deutlich mehr Ressourcen als die Levels READ COMMITTED oder REPEATABLE READ. Warum? PostgreSQL muss die Ausführung so tun, als ob alles nacheinander passiert, und alle möglichen Konflikte zwischen Transaktionen überwachen.

Serialisierungsfehler
Wenn PostgreSQL merkt, dass Transaktionen nicht in der "perfekten Reihenfolge" ausgeführt werden können, wirft es einen Serialisierungsfehler (serialization_failure) und rollt die Transaktion zurück.

Beispiel für einen Fehler:

ERROR: could not serialize access due to concurrent update

Um mit solchen Situationen klarzukommen, kannst du die Transaktion nach einem Fehler einfach nochmal starten:

DO $$
DECLARE
    done BOOLEAN := FALSE;
BEGIN
    WHILE NOT done LOOP
        BEGIN
            -- Transaktion starten
            BEGIN;
            SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;

            -- Operationen ausführen
            UPDATE accounts SET balance = balance - 100 WHERE id = 1;

            -- Änderungen bestätigen
            COMMIT;
            done := TRUE; -- Aus der Schleife raus, wenn alles geklappt hat
        EXCEPTION WHEN serialization_failure THEN
            ROLLBACK; -- Bei Fehler zurückrollen
        END;
    END LOOP;
END;
$$;

Das ist ein gängiger Ansatz in Systemen, die SERIALIZABLE nutzen.

Wichtig!

Dieser Code ist mit PL-SQL geschrieben. Wir kommen später nochmal darauf zurück. Ich wollte dir einfach mal schönen und funktionierenden Code zeigen. Und auch, warum man PL-SQL braucht :)

Wann solltest du SERIALIZABLE verwenden?

Dieses Isolationslevel macht Sinn, wenn Fehler richtig teuer werden können:

  • Finanztransaktionen, wie Zahlungsabwicklung oder Bonusverteilung.
  • Bestandsverwaltungssysteme, um doppelte Bestellungen zu vermeiden.
  • Online-Buchungen, wo Konflikte bei der Reservierung von Ressourcen ausgeschlossen werden müssen.

Wenn du ein System baust, bei dem die Daten zu 100% konsistent sein müssen und Performance nicht das Wichtigste ist, dann wird SERIALIZABLE dein bester Freund.

Kommentare
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION