Two transactions, opposite order
A deadlock happens when transaction A holds a lock on row X and waits for row Y, while transaction B holds Y and waits for X. Neither can proceed. PostgreSQL detects the cycle and aborts one of them (40P01 deadlock_detected error).
The deadlock recipe
Two updates, two rows, accessed in opposite orders. Almost every deadlock in real systems is some variation of this pattern.
Two preventions
- Always update rows in the same order across all code paths. If you always touch row 1 then row 2, you can never deadlock with another transaction doing the same.
- Catch and retry. Deadlocks are sometimes unavoidable in real workloads. Wrap your transaction in a retry loop (with backoff) and treat 40P01 as a recoverable error.