Concept lesson

Locking, Deadlocks & Advisory Locks

Table and row-level locks, deadlock detection graphs, PostgreSQL application advisory locks, and pessimistic concurrency.

lesson
Freshness: current15 min read
Mastery
not started · 0%

Learning outcomes

  • Resolve transaction deadlock chains
  • Protect critical sections using application advisory locks

Mental model

PostgreSQL manages concurrent access through a hierarchy of lock modes ranging from ACCESS SHARE (concurrent reads) to ACCESS EXCLUSIVE (exclusive table DDL modification).

Transaction A acquires Row Lock 1
Transaction B acquires Row Lock 2
Tx A requests Row Lock 2 (Blocked)
Tx B requests Row Lock 1 (Deadlock)
PostgreSQL Deadlock Detector cancels Tx B
Conceptual teaching model synthesized from:PostgreSQL 16 Architecture, MVCC & Query Optimization Manual

Theory

When two transactions wait for locks held by each other, a Deadlock occurs. PostgreSQL's background deadlock detector inspects lock dependency graphs after deadlock_timeout (default 1s) and aborts one of the transactions with a deadlock detected error.

Application developers can also leverage PostgreSQL Advisory Locks (pg_advisory_lock(key)) to create application-level mutexes without creating dummy database rows.

-- Acquire transactional row lock
SELECT * FROM inventory WHERE item_id = 501 FOR UPDATE;

-- Application-level advisory lock (session-scoped)
SELECT pg_advisory_lock(123456);
-- ... Execute critical section ...
SELECT pg_advisory_unlock(123456);

-- Non-blocking try-lock for distributed workers
SELECT pg_try_advisory_lock(7890);

Alternatives and trade-offs

  • Optimistic Concurrency: Uses version numbers (WHERE version = 1). Great for low contention; fails under heavy concurrent updates.
  • Pessimistic Row Locks (FOR UPDATE): Prevents concurrent updates; risks deadlocks if lock acquisition order varies.
  • Advisory Locks: Light-weight, zero-table-overhead application mutexes.

Failure modes and misconceptions

  1. Inconsistent Lock Acquisition Order: Transaction A locks Account 1 then Account 2; Transaction B locks Account 2 then Account 1. This guarantees deadlocks under high concurrency. Always sort entity IDs before acquiring locks.
  2. Leaking Session Advisory Locks: Failing to call pg_advisory_unlock() on session-scoped locks leaves locks active until connection termination.
Reflect before revealing the guide

Decision scenario

Use pg_try_advisory_lock(job_id) in background worker cron tasks to ensure only a single worker instance executes a distributed task at any given time.

Learning outcomes

  • Classify table and row-level lock conflict matrices in PostgreSQL.
  • Prevent deadlocks by enforcing deterministic lock acquisition ordering.
  • Implement distributed application locks using pg_advisory_lock.

Trade-offs

Pessimistic row locks guarantee strict data consistency under concurrent modifications, but increase transaction waiting times and deadlock risks.

Evidence assessment

Theory and decision mastery

not-started · 0%
theory0%
decision0%
activityNot mapped
projectNot mapped
1. How does PostgreSQL handle deadlocks when two transactions wait for locks held by each other?
2. What is the primary advantage of PostgreSQL Advisory Locks (pg_advisory_lock)?
3. Which SQL clause explicitly acquires a pessimistic row-level write lock during a SELECT query?

Decision scenario

A financial application encounters periodic deadlock errors when executing concurrent fund transfers between user accounts.

Which application design pattern prevents transaction deadlocks during multi-row transfers?

Primary sources