Advisory Locks für anwendungsseitige Koordination
AI generated
SELECT
JOIN
SQL / Locking
Advisory Locks für anwendungsseitige Koordination
wie Anwendungslogik statt Datenzeilen koordiniert wird

Datenbanksperren schützen üblicherweise konkrete Datenzeilen oder Tabellen vor gleichzeitigem, inkonsistentem Zugriff. Advisory Locks verfolgen einen anderen Zweck: Sie nutzen dieselbe robuste Locking-Infrastruktur der Datenbank, um beliebige Anwendungslogik zu koordinieren, ohne dass diese Sperre an eine konkrete Zeile oder Tabelle gebunden ist. Ein typischer Einsatzfall ist verteiltes Locking für Cron-Jobs oder Hintergrundprozesse, die auf mehreren Servern laufen könnten, aber niemals gleichzeitig denselben Vorgang ausführen dürfen.

10 Min. Lesezeit Advisory Locks Verteiltes Locking

1. Der Unterschied zu klassischen Zeilen- und Tabellensperren

Eine klassische Sperre in einer relationalen Datenbank ist immer an ein konkretes Datenobjekt gebunden: eine Zeile, eine Seite oder eine ganze Tabelle. Diese Sperren entstehen implizit durch normale DML-Anweisungen wie UPDATE oder explizit durch SELECT FOR UPDATE, und ihr Zweck ist es, konkurrierende Änderungen an denselben Daten zu koordinieren, damit die Konsistenz der gespeicherten Werte erhalten bleibt.

Ein Advisory Lock ist dagegen vollständig von konkreten Daten entkoppelt. Er besteht lediglich aus einer numerischen oder textuellen Kennung, die von der Anwendung frei gewählt wird, und trägt selbst keinerlei semantische Bedeutung für die Datenbank. Die Datenbank garantiert nur, dass zu jedem Zeitpunkt höchstens ein Prozess einen exklusiven Advisory Lock mit derselben Kennung halten kann, unabhängig davon, wofür diese Kennung inhaltlich steht.

2. Das Grundprinzip: eine beliebige Kennung als Koordinationspunkt

Weil ein Advisory Lock keine Verbindung zu konkreten Tabellenzeilen hat, kann er für jede Art von Koordinationsproblem genutzt werden, das die Anwendung selbst definiert: das Verhindern doppelter Batch-Verarbeitung, die Serialisierung eines bestimmten Geschäftsvorgangs über mehrere Serverinstanzen hinweg, oder ein einfacher, verteilter Mutex für eine kritische Initialisierungsroutine, die nur einmal laufen darf.

Die Kennung selbst wird üblicherweise aus einem stabilen, fachlich sprechenden Wert abgeleitet, etwa durch Hashing eines Job-Namens oder einer Mandanten-ID auf eine ganze Zahl, damit dieselbe Kennung bei jedem Aufruf konsistent reproduzierbar ist. Zwei unterschiedliche Prozesse, die denselben logischen Vorgang koordinieren wollen, müssen sich dabei nur auf dieselbe Ableitungslogik für die Kennung einigen, nicht auf ein gemeinsames Datenschema.


-- Advisory Lock über eine numerische Kennung anfordern (Syntax exemplarisch)
SELECT pg_try_advisory_lock(hashtext('nightly-report-job'));

-- Alternative in anderen Systemen über eine benannte Sperre
SELECT GET_LOCK('nightly-report-job', 10);
-- zweiter Parameter: maximale Wartezeit in Sekunden

3. Praktischer Anwendungsfall: Cron-Jobs, die nicht doppelt laufen dürfen

Ein klassisches Problem in verteilten Systemen ist ein zeitgesteuerter Job, der auf mehreren, redundant ausgelegten Servern eingeplant ist, aber inhaltlich nur einmal pro Ausführungszeitpunkt laufen darf, etwa ein nächtlicher Report-Export oder eine Abrechnungsbatch. Ohne Koordination würde jeder Server den Job unabhängig starten, was zu doppelter Verarbeitung, inkonsistenten Ergebnissen oder doppelt verschickten E-Mails führen kann.

Ein Advisory Lock löst dieses Problem elegant, ohne eine separate Koordinationsinfrastruktur wie einen dedizierten verteilten Lock-Service zu benötigen: Jeder Server versucht zu Beginn des Jobs, denselben Advisory Lock zu erwerben. Nur der Server, der die Sperre tatsächlich erhält, führt den Job aus, alle anderen erkennen den Fehlschlag sofort und beenden sich, ohne zu blockieren oder eine eigene Fehlerbehandlung für einen doppelten Lauf implementieren zu müssen.


-- Nicht-blockierender Versuch, den Job-Lock zu erwerben
DO $$
BEGIN
    IF pg_try_advisory_lock(hashtext('billing-export-2026-08-08')) THEN
        -- Nur dieser Prozess führt den Export aus
        PERFORM run_billing_export();
        PERFORM pg_advisory_unlock(hashtext('billing-export-2026-08-08'));
    ELSE
        RAISE NOTICE 'Export läuft bereits auf einer anderen Instanz';
    END IF;
END $$;

4. Session-Level-Locks: manuelle Freigabe und Verbindungsbindung

Ein Session-Level Advisory Lock bleibt so lange bestehen, bis er entweder explizit über einen Unlock-Befehl freigegeben wird oder die Datenbankverbindung, die ihn erworben hat, beendet wird. Diese Bindung an die Verbindung, nicht an eine einzelne Transaktion, macht Session-Level-Locks geeignet für Koordinationsaufgaben, die über mehrere Transaktionen hinweg gelten sollen, etwa das Sperren eines gesamten mehrstufigen Batch-Vorgangs, der intern mehrere Commits ausführt.

Der wichtigste operative Punkt dabei: Wird die Verbindung durch einen Absturz oder eine unsauber terminierte Anwendung unterbrochen, ohne dass explizit entsperrt wurde, gibt die Datenbank den Lock automatisch frei, sobald sie das Verbindungsende erkennt. Dieses Verhalten verhindert einen dauerhaft hängenden Lock, erfordert aber, dass Connection-Pooling-Schichten korrekt konfiguriert sind, damit eine Verbindung nicht fälschlich als aktiv weiterverwendet wird, während der ursprachliche Prozess bereits beendet ist.

5. Transaction-Level-Locks: automatische Freigabe am Transaktionsende

Ein Transaction-Level Advisory Lock wird automatisch freigegeben, sobald die aktuelle Transaktion committet oder zurückgerollt wird, unabhängig davon, ob explizit entsperrt wurde. Diese Variante eignet sich für Koordinationsprobleme, die exakt an die Lebensdauer einer einzelnen Transaktion gebunden sind, etwa das Serialisieren eines kritischen Abschnitts innerhalb einer einzelnen Geschäftsoperation, ohne das Risiko, einen manuellen Unlock-Aufruf zu vergessen.

Der Vorteil gegenüber Session-Level-Locks liegt in der geringeren Fehleranfälligkeit: Ein vergessener oder durch eine Exception übersprungener Unlock-Aufruf kann bei Session-Level-Locks zu einem dauerhaft blockierten Koordinationspunkt führen, während ein Transaction-Level-Lock durch das ohnehin garantierte Transaktionsende zuverlässig aufgeräumt wird, selbst wenn die Anwendung einen Fehlerfall nicht sauber behandelt.


-- Transaction-Level Advisory Lock: automatische Freigabe bei COMMIT/ROLLBACK
BEGIN;
SELECT pg_advisory_xact_lock(hashtext('reindex-catalog'));
-- kritischer Abschnitt
UPDATE catalog_state SET reindex_running = true;
-- ... Verarbeitung ...
COMMIT;
-- Lock wird spätestens hier automatisch freigegeben

6. Blockierende vs. nicht-blockierende Varianten richtig einsetzen

Die meisten Datenbanksysteme bieten sowohl eine blockierende Variante an, die wartet, bis die Sperre verfügbar wird, als auch eine nicht-blockierende Variante, die sofort mit einem Erfolgs- oder Fehlschlag-Wert zurückkehrt. Für den Cron-Job-Anwendungsfall ist fast immer die nicht-blockierende Variante die richtige Wahl, weil ein Prozess, der die Sperre nicht erhält, den Job schlicht überspringen soll, statt ungenutzt zu warten und Ressourcen zu binden.

Blockierende Varianten eignen sich dagegen für Fälle, in denen mehrere Prozesse tatsächlich nacheinander denselben kritischen Abschnitt durchlaufen sollen, etwa eine sequentielle Verarbeitungspipeline mit mehreren Arbeitern. Wird hier fälschlich die nicht-blockierende Variante verwendet, brechen Arbeiter bei Konkurrenz sofort ab, statt korrekt in der Warteschlange zu bleiben, was die beabsichtigte Serialisierung unterläuft.

7. Häufige Fehler beim praktischen Einsatz von Advisory Locks

Ein verbreiteter Fehler ist die Kollision von Kennungen: Wird derselbe Zahlenraum für unterschiedliche, inhaltlich unabhängige Koordinationszwecke genutzt, etwa weil zwei Teams denselben Hashing-Ansatz ohne gemeinsame Absprache verwenden, kann es zu Kollisionen kommen, bei denen ein Lock fälschlich als belegt erscheint, obwohl er fachlich für einen anderen Zweck gedacht war. Ein klarer Namensraum, etwa durch ein Präfix vor dem Hashing, vermeidet dieses Problem zuverlässig.

Ein zweiter häufiger Fehler ist die Verwechslung von Session- und Transaction-Level-Locks in Umgebungen mit Connection Pooling: Wird eine Verbindung nach Freigabe an den Pool zurückgegeben, ohne dass ein Session-Level-Lock explizit entsperrt wurde, bleibt der Lock aus Sicht der Datenbank aktiv, obwohl die Anwendung ihn logisch als beendet betrachtet, bis eine neue Anfrage zufällig dieselbe gepoolte Verbindung wiederverwendet und den Lock unbewusst weiterhält.

8. Aktive Advisory Locks im Betrieb beobachten und debuggen

Weil Advisory Locks keine Verbindung zu konkreten Tabellenzeilen haben, tauchen sie nicht in denselben Diagnosewerkzeugen auf wie klassische Zeilensperren. Die meisten Systeme bieten dafür eine eigene Systemsicht oder Funktion, die aktuell gehaltene Advisory Locks samt ihrer Kennung und der haltenden Sitzung auflistet, was bei der Fehlersuche nach einem vermeintlich hängenden Koordinationspunkt der erste Anlaufpunkt sein sollte.

Für produktive Systeme empfiehlt sich zusätzlich ein Timeout oder eine maximale Wartezeit bei blockierenden Varianten, damit ein fehlerhaft hängender Lock nicht zu einer unbegrenzt wartenden Prozesskette führt. Kombiniert mit einem Logging, das jeden Erwerb und jede Freigabe eines Advisory Locks mit Zeitstempel protokolliert, lässt sich ein hängender Koordinationspunkt im Nachhinein zuverlässig auf seinen ursprünglichen Prozess zurückverfolgen.


-- Aktuell gehaltene Advisory Locks anzeigen (Syntax exemplarisch)
SELECT locktype, objid, pid, granted
FROM pg_locks
WHERE locktype = 'advisory';

9. Wann Advisory Locks die falsche Wahl sind

Advisory Locks sind kein Ersatz für klassische Zeilensperren oder Unique Constraints, wenn es tatsächlich um die Konsistenz gespeicherter Daten geht. Soll verhindert werden, dass zwei Prozesse denselben Datensatz gleichzeitig widersprüchlich ändern, ist ein reguläres Locking-Konzept auf Datenebene, etwa optimistisches Locking mit einer Versionsspalte oder SELECT FOR UPDATE, die korrektere und robustere Lösung, weil die Datenbank diese Garantien dann direkt an den betroffenen Daten durchsetzt.

Advisory Locks eignen sich dagegen genau dort, wo kein konkretes Datenobjekt existiert, das gesperrt werden könnte, die Koordination aber trotzdem eine zuverlässige, verteilte Infrastruktur benötigt, wie es bei rein prozess- oder job-bezogener Koordination der Fall ist. Diese klare Abgrenzung nach Anwendungsfall, nicht nach technischer Bequemlichkeit, verhindert einen Missbrauch von Advisory Locks als generisches Ersatz-Locking für eigentlich datenbezogene Probleme.

Aspekt Session-Level Lock Transaction-Level Lock Praxis-Hinweis
Freigabe Manuell oder bei Verbindungsende Automatisch bei COMMIT/ROLLBACK Transaction-Level ist fehlertoleranter
Bindung An die Datenbankverbindung An die aktuelle Transaktion Wichtig bei Connection Pooling
Typischer Einsatz Mehrstufige Batch-Prozesse Einzelne kritische Operation Nach Lebensdauer des Vorgangs wählen
Risiko bei Fehler Vergessener Unlock hängt dauerhaft Wird beim Transaktionsende aufgeräumt Session-Level braucht disziplinierten Code
Blockierend vs. nicht Beide Varianten verfügbar Beide Varianten verfügbar Nicht-blockierend für Cron-Jobs
Datenbezug Keiner, freie Kennung Keiner, freie Kennung Kein Ersatz für Zeilensperren

Mironsoft

Datenbank-Optimierung, Query-Tuning und Migrationen

SQL-Abfragen, die bei Wachstum immer langsamer werden?

Wir analysieren und optimieren SQL-Datenbanken unabhängig vom eingesetzten System, planen sichere Migrationen und Schema-Änderungen und bringen Teams Query-Optimierung praxisnah bei.

Query-Optimierung

Langsame Abfragen analysieren und mit Indizes und Explain-Plänen gezielt beschleunigen.

Migrations-Planung

Schema-Änderungen und Datenmigrationen sicher und ohne Downtime umsetzen.

Team-Schulung

SQL-Grundlagen und Performance-Denken praxisnah im Entwicklerteam verankern.

10. Zusammenfassung

Advisory Locks: Das Wichtigste auf einen Blick

Grundidee

Advisory Locks nutzen die Locking-Infrastruktur der Datenbank, um Anwendungslogik statt Datenzeilen zu koordinieren.

Hauptanwendung

Verteiltes Locking für Cron-Jobs oder Hintergrundprozesse, die nicht gleichzeitig auf mehreren Servern laufen dürfen.

Session vs. Transaction

Session-Level braucht manuelle Freigabe und hängt an der Verbindung, Transaction-Level räumt sich am Transaktionsende automatisch auf.

Abgrenzung

Kein Ersatz für Zeilensperren oder Unique Constraints bei echten Datenkonsistenz-Problemen.

11. FAQ: Advisory Locks: Das Wichtigste auf einen Blick

1Was unterscheidet einen Advisory Lock von einer klassischen Zeilensperre?
Eine klassische Zeilensperre ist an ein konkretes Datenobjekt gebunden, ein Advisory Lock besteht nur aus einer frei gewählten Kennung ohne jede Verbindung zu Tabellendaten und dient allein der anwendungsseitigen Koordination.
2Wofür eignen sich Advisory Locks typischerweise?
Für verteiltes Locking bei Cron-Jobs oder Hintergrundprozessen, die auf mehreren Servern laufen könnten, aber niemals gleichzeitig denselben Vorgang ausführen dürfen, sowie für beliebige andere anwendungsseitige Koordinationsprobleme.
3Was ist der Unterschied zwischen Session-Level und Transaction-Level Locks?
Ein Session-Level Lock bleibt bis zum expliziten Unlock oder Verbindungsende bestehen, ein Transaction-Level Lock wird automatisch bei COMMIT oder ROLLBACK der aktuellen Transaktion freigegeben.
4Warum ist die nicht-blockierende Variante für Cron-Jobs meist richtig?
Weil ein Prozess, der die Sperre nicht erhält, den Job einfach überspringen soll, statt untätig zu warten und Ressourcen zu binden. Die nicht-blockierende Variante liefert sofort einen Erfolgs- oder Fehlschlag-Wert.
5Was passiert, wenn eine Verbindung mit aktivem Session-Level-Lock abstürzt?
Die Datenbank erkennt das Verbindungsende und gibt den Lock automatisch frei, wodurch ein dauerhaft hängender Lock verhindert wird. Bei Connection Pooling muss dieses Verhalten aber berücksichtigt werden.
6Können Advisory Locks Zeilensperren oder Unique Constraints ersetzen?
Nein. Für echte Datenkonsistenz-Probleme sind reguläre Sperrmechanismen wie optimistisches Locking oder SELECT FOR UPDATE die korrektere Lösung, weil die Datenbank diese Garantien direkt an den Daten durchsetzt.
7Wie vermeidet man Kollisionen zwischen verschiedenen Advisory-Lock-Kennungen?
Durch einen klaren Namensraum, etwa ein festes Präfix vor dem Hashing der fachlichen Kennung, sodass unterschiedliche Koordinationszwecke nicht versehentlich denselben Zahlenraum nutzen.
8Wie lassen sich aktive Advisory Locks im Betrieb einsehen?
Über eine systemeigene Sicht oder Funktion, die aktuell gehaltene Advisory Locks samt Kennung und haltender Sitzung auflistet, verfügbar in den meisten gängigen Datenbanksystemen.
9Was ist ein häufiger Fehler bei Connection Pooling und Advisory Locks?
Ein Session-Level-Lock bleibt aktiv, wenn die Verbindung ohne expliziten Unlock an den Pool zurückgegeben wird, bis eine neue Anfrage dieselbe gepoolte Verbindung zufällig wiederverwendet und den Lock unbewusst weiterhält.
10Sollte man für jede Koordinationsaufgabe Advisory Locks nutzen?
Nur wenn kein konkretes Datenobjekt existiert, das gesperrt werden könnte. Für datenbezogene Konsistenzprobleme sind klassische, datenbezogene Sperrmechanismen weiterhin die richtige Wahl.