how to choose which one? šŸ˜µā€šŸ’«

Dimension Optimistic (no blocking, detect & retry) Pessimistic (block first, then proceed)
Expected conflict rate Low – most concurrent Tx-ns touch different rows or only read. High – the same rows are updated a lot (inventory counters, queue tables, hot accounts).
Tx-n length / latency Short, in-memory work āž” cheap to retry. Long-running units (minutes …) – retry would waste too much work.
System load Spare capacity to absorb occasional retries. System already near saturation – retries would make it worse.
Hold user input? No (everything computed server-side). Yes – e.g., interactive ā€œedit form āžœ saveā€ flows where the user might collide.
Isolation level used Snapshot / MVCC, version-columns, compare-and-set, SSI. SELECT … FOR UPDATE, 2-phase locking, explicit row/table locks.
Failure handling Must detect conflict (ERR_CONFLICT) and retry in code (with back-off). App just blocks until the lock is free—no retry logic needed (but might need a timeout).
Throughput & scaling Scales well: readers never block writers, writers never block readers. Lock wait chains can hurt p-99 latency; limited by contention on hot rows.
Typical use-cases • Micro-services writing distinct rows• Event-sourced append logs• Read-heavy analytics queries on snapshots• ā€œShopping-cartā€ merges in doc DBs • Bank account debits/credits• Warehouse stock decrement• Job queues / ā€œtake-next-jobā€ pattern• Anything that must be strictly sequential

Rules of thumb

  1. Measure conflict probability

    If two updates on the same row are rare (<1 %) → optimistic is simpler and faster.

    Frequent clashes (>~10 %) → pessimistic avoids thrashing.

  2. How painful is a retry?

    Milliseconds of CPU → optimistic.

    Heavy calculations, external calls, or user think-time → pessimistic.

  3. Do you hold a lock across network hops?

    Cross-service calls while a DB lock is held = danger; optimistic (or split Tx-ns) is safer.

  4. Hot-spot keys (global counters, single ā€œsettingsā€ row) almost always need pessimistic or an atomic DB primitive.


Hybrid approach

Many production systems mix both:


Bottom line

Use optimistic when conflicts are unlikely and retries are cheap; switch to pessimistic (or atomic DB primitives) when the same rows are hammered, work is expensive, or business correctness can’t tolerate a retry loop.