CodeGym /Kurse /SQL SELF /Einschränkungen und potenzielle Probleme bei der Arbeit m...

Einschränkungen und potenzielle Probleme bei der Arbeit mit Transaktionen: LOCK, DEADLOCK

SQL SELF
Level 54 , Lektion 1
Verfügbar

Transaktionen in PostgreSQL sorgen für Isolation – das ist eines der wichtigsten Merkmale von ACID. Dafür nutzt das System Locks. Ein Lock ist ein Mechanismus, der garantiert, dass mehrere Transaktionen sich nicht um denselben Datensatz oder dieselbe Tabelle "prügeln". Stell dir eine Schlange im Supermarkt vor: An der Kasse wird immer nur eine Person bedient. Locks funktionieren ähnlich, nur dass sie den Zugriff auf Daten in Tabellen steuern.

Die wichtigsten Lock-Typen

In PostgreSQL gibt es verschiedene Arten von Locks, einige davon hast du vielleicht schon mal in EXPLAIN ANALYZE gesehen:

  1. ROW EXCLUSIVE (Zeilen-exklusives Lock) – tritt auf, wenn Daten in einer Zeile geändert werden. Das ist der am häufigsten genutzte Lock-Typ, zum Beispiel bei INSERT, UPDATE oder DELETE.
  2. SHARE (Shared Lock) – wird für Operationen genutzt, die garantieren, dass die Daten während der Anfrage nicht geändert werden, zum Beispiel bei SELECT ... FOR SHARE.
  3. EXCLUSIVE (Exklusives Lock) – verhindert alle anderen Operationen mit den Daten außer Lesen.

Man kann sagen, Locks sind so etwas wie Wachhunde, die unsere Daten bewachen.

Das Problem mit Locks: Was kann schiefgehen?

Jetzt, wo wir wissen, was Locks sind, schauen wir uns an, welche Probleme sie verursachen können. Das größte Problem ist der Deadlock. Ein Deadlock ist eine Situation, in der zwei (oder mehr) Transaktionen aufeinander warten, sodass alles in einer Endlosschleife festhängt. Typischerweise sieht das so aus:

  1. Transaktion 1 sperrt Zeile A und will auf Zeile B zugreifen.
  2. Transaktion 2 sperrt Zeile B und will auf Zeile A zugreifen.
  3. Da beide Zeilen gesperrt sind, kann keine der Transaktionen abgeschlossen werden.

Beispiel für einen Deadlock

Um den Schmerz eines Programmierers zu spüren, der auf einen Deadlock trifft, stell dir folgendes Szenario vor:

-- Transaktion 1
BEGIN;
UPDATE accounts SET balance = balance - 100 WHERE id = 1;

-- Gleichzeitig
-- Transaktion 2
BEGIN;
UPDATE accounts SET balance = balance + 200 WHERE id = 2;

-- Transaktion 1 versucht, id = 2 zu sperren
UPDATE accounts SET balance = balance - 100 WHERE id = 2;

-- Transaktion 2 versucht, id = 1 zu sperren
UPDATE accounts SET balance = balance + 200 WHERE id = 1;

Voilà! Jede Transaktion ist von der anderen blockiert. PostgreSQL erkennt das irgendwann und wirft einen Deadlock-Fehler.

Wie kann man Deadlocks vermeiden?

  1. Immer die gleiche Reihenfolge beim Datenzugriff. Versuche immer, auf Daten in derselben Reihenfolge zuzugreifen. Wenn Transaktion 1 zuerst Zeile A und dann Zeile B sperrt, sollte Transaktion 2 genauso vorgehen: erst Zeile A, dann Zeile B.
-- Richtige Reihenfolge beim Zugriff
BEGIN;
UPDATE accounts SET balance = balance - 100 WHERE id = 1;
UPDATE accounts SET balance = balance + 200 WHERE id = 2;
COMMIT;
  1. Halte Transaktionen so kurz wie möglich. Lange Transaktionen erhöhen die Wahrscheinlichkeit eines Deadlocks. Beende Transaktionen so schnell wie möglich: BEGIN, alle nötigen Änderungen machen und sofort COMMIT.

  2. Nutze die passenden Isolation Levels. Wenn du keine strenge Isolation brauchst, überlege, ob du das Isolation Level READ COMMITTED verwendest. Das hilft, manche Locks zu vermeiden.

Timeouts und Lock-Diagnose

Es gibt Tools, um Locks in PostgreSQL zu diagnostizieren und zu verhindern. Zum Beispiel kannst du eine maximale Wartezeit für Locks setzen:

SET lock_timeout = '5s';  -- Setze das Lock-Timeout auf 5 Sekunden

Wenn ein Lock länger gehalten wird als angegeben, wird die Transaktion abgebrochen – das verhindert einen kompletten Stillstand.

Locks in PostgreSQL überwachen

Einer der nützlichen Befehle zum Überwachen von Locks ist pg_locks. Damit siehst du alle aktiven Locks im System:

SELECT * FROM pg_locks;

Du kannst sehen, welche Transaktionen Locks halten und welche darauf warten. Das ist besonders hilfreich beim Debuggen von Deadlocks.

Besonderheiten von LOCK und manuelles Sperren von Objekten

Wenn du Locks manuell steuern willst, nutze den Befehl LOCK:

LOCK TABLE orders IN ACCESS EXCLUSIVE MODE;

Achtung: ACCESS EXCLUSIVE ist das stärkste Lock – es verbietet alle anderen Operationen auf der Tabelle, sogar SELECT. Nutze das nur in Spezialfällen (zum Beispiel beim Ändern der Tabellenstruktur).

Um einzelne Zeilen beim Ändern zu sperren, nutze SELECT ... FOR UPDATE:

SELECT * FROM accounts WHERE id = 1 FOR UPDATE;

Das garantiert, dass andere Transaktionen diese Zeilen bis zum Ende deiner Transaktion nicht ändern können.

Was solltest du über Locks wissen?

Locks sind kein Übel, sondern ein Werkzeug. Sie helfen, die Datenintegrität zu bewahren, aber man muss mit ihnen vorsichtig umgehen. Hier ein paar wichtige Tipps:

  1. Starte keine Transaktion, wenn du nicht genau weißt, warum du sie brauchst.
  2. Beende Transaktionen so schnell wie möglich.
  3. Greife nicht in unterschiedlicher Reihenfolge auf Daten zu.
  4. Nutze das Isolation Level, das zu deiner Aufgabe passt.

Jetzt bist du bereit für den Umgang mit Locks und Deadlocks! Möge pg_locks und die Weisheit von ACID mit dir sein.

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