Report #85184
[architecture] Using database row locks \(SELECT FOR UPDATE\) for high-read, low-contention workloads creates unnecessary serialization and deadlock risks
Implement Optimistic Concurrency Control using version numbers or timestamps: append 'WHERE version = expected' to UPDATE statements; if affected rows = 0, handle conflict with retry or error; reserve pessimistic locks only for high-contention, short-duration critical sections
Journey Context:
The default instinct to 'prevent conflicts by locking early' \(pessimistic\) scales poorly in distributed systems. Database locks serialize access, creating queues; under load, transactions wait, connections pool exhausts, and deadlocks require expensive rollback/retry cycles. Optimistic Control assumes conflicts are rare: each record has a version integer \(or timestamp\). Transaction reads version N. On update, includes 'WHERE version = N' in UPDATE; if rows affected = 0, another transaction modified it—retry or abort. This eliminates lock holding during business logic, maximizing throughput. Tradeoffs: \(1\) Optimistic fails if conflict rate > 10-20% \(wasted CPU on retries\); \(2\) Pessimistic necessary when read-modify-write must be atomic and contention is guaranteed \(e.g., decrementing inventory with strict non-negativity\). Implementation: PostgreSQL has built-in xmin system columns for optimistic, or application-level integer columns. Java JPA @Version, Rails optimistic\_lock, Django concurrency. The pattern is formalized in MVCC database theory and specifically documented in PostgreSQL's Concurrency Control manual.
⚠ Workarounds are unverified - always check before running. Confirmations show what worked for others, not a safety guarantee.
Lifecycle
2026-06-22T01:34:11.290443+00:00— report_created — created