To manage concurrent access to database records, preventing race conditions and data inconsistencies (e.g., double spending, overbooking).
- Financial transactions.
- Inventory management.
- "Check-and-Set" operations.
Assume conflict is rare. Use a version column.
- Read record:
SELECT * FROM products WHERE id=1;(Returns version: 5) - Update with check:
UPDATE products SET stock = stock - 1, version = 6 WHERE id = 1 AND version = 5;
- Check result: If "0 rows affected", someone else modified it. Retry or throw error.
Implementation (TypeORM/Prisma):
Often supported natively (@VersionColumn in TypeORM).
Assume conflict is likely. Lock the row for the transaction duration.
- Start Transaction.
- Select for Update:
(This blocks other transactions trying to lock this row).
SELECT * FROM products WHERE id = 1 FOR UPDATE;
- Perform Logic.
- Commit (Release Lock).
Lock an arbitrary abstract name/ID, not a specific row.
-- PostgreSQL
SELECT pg_advisory_xact_lock(12345);
-- Do work...
-- Lock released automatically at end of transaction- Deadlocks: Pessimistic locking can lead to deadlocks if two transactions lock resources in reverse order. Always acquire locks in a consistent order (e.g., sort by ID).
- Performance:
FOR UPDATEreduces concurrency. Use Optimistic locking for high-traffic, low-conflict scenarios.
Data integrity guarantees under high concurrency, ensuring atomic transitions of state.