Concurrency bugs are dangerous because the system can look healthy while quietly losing somebody’s work.
Two processes read the same record. Both make valid changes. The second write overwrites the first because neither process knew the other had changed the data.
Optimistic and pessimistic locking are two common ways to prevent that kind of collision.
What is optimistic locking?
Optimistic locking allows several readers to work with the same data without holding a long lock. When an update is written, the system checks whether the record has changed since it was read.
A common implementation uses a version number, timestamp, or another concurrency marker. The update succeeds only if the expected version is still current.
If another process changed the record first, the write is rejected as a conflict. The application then decides whether to retry, reload the data, merge changes, or ask the user to reconsider.
What is pessimistic locking?
Pessimistic locking prevents competing operations from changing the same protected data at the same time by acquiring a lock before the critical work completes.
Other operations may wait until the lock is released. This reduces the chance of a business conflict reaching the application, but it consumes concurrency and creates lock-management problems.
The system is effectively saying: this operation is important enough that I would rather make somebody else wait than discover a conflict later.
Optimistic vs pessimistic locking in one sentence
Optimistic locking pays when a conflict actually happens. Pessimistic locking pays in waiting even when a conflict might never happen.
That is why the right choice depends less on ideology and more on traffic, conflict frequency, transaction length, and the cost of getting a collision wrong.
A simple optimistic-locking example
An employee opens a customer record at version 12. Another employee updates it, producing version 13. The first employee then submits changes based on version 12.
Without concurrency control, those changes can overwrite the newer state. With optimistic locking, the update says in effect: “write this only if the record is still version 12.” It is not, so the conflict becomes visible instead of silent.
The hard part is what happens next. A generic automatic retry may be wrong if a person needs to see the changed data before making the decision again.
A simple pessimistic-locking example
A short transaction is changing a scarce resource where two simultaneous decisions must not proceed independently.
The transaction obtains a lock, verifies the current state, makes the change, and releases the lock. Another transaction touching the same protected resource waits or fails according to the database and application behavior.
This can be appropriate when the critical section is short and a collision would be costly. It becomes expensive when locks are held for too long or too many operations compete for the same records.
What does the business gain?
The business gets explicit protection against lost updates and other concurrency errors that can create wrong prices, duplicated decisions, overwritten work, or inconsistent state.
The choice also affects throughput and customer experience. A locking strategy is not only a database setting; it determines whether users wait, see a conflict, retry, or receive an error.
Where optimistic locking works well
- conflicts are relatively rare;
- reads and edits may take a long time, so holding a database lock across the whole user interaction would be unreasonable;
- the application can present a conflict clearly or safely retry a short technical operation;
- high concurrency matters more than preventing every possible conflict in advance.
Where pessimistic locking can make sense
- conflicts are frequent enough that optimistic retries become expensive;
- the protected operation is short;
- the cost of two operations proceeding concurrently is high;
- waiting is an acceptable customer or system behavior;
- the database transaction can own the critical decision cleanly.
What can go wrong with optimistic locking?
Retry storms. If contention becomes high, many updates can fail and retry repeatedly.
Bad UX. Telling a user “something went wrong” is not enough when the actual issue is “someone changed this record while you were editing it.”
Unsafe automatic retries. Not every business decision should be silently repeated against new data.
Ignoring conflict metrics. A strategy chosen when traffic was small may become inefficient when the same records become hot.
What can go wrong with pessimistic locking?
Long waits. One slow transaction can block many others.
Deadlocks. Two transactions can wait for resources held by each other. The application still needs error handling when one transaction is aborted.
Lower throughput. A frequently locked record can become a serialization point for the whole business flow.
Operational surprises. Lock contention often appears under real load rather than in ordinary functional testing.
Do not confuse locking with idempotency
Locking coordinates concurrent access to state. Idempotency protects against repeating the same logical operation, often because of retries or duplicate delivery.
A payment flow may need both. Preventing two transactions from editing the same row is not automatically the same as preventing the same external request from charging twice.
Measure the choice instead of debating it forever
The useful signals are observable: optimistic conflict rate, retry count, lock wait time, deadlocks, transaction duration, and the number of customer-visible conflicts.
If optimistic conflicts stay rare, paying the cost only when they happen is efficient. If one hot record creates constant retries, stronger coordination or a different data model may be needed.
If pessimistic locks create long queues, the system may be protecting consistency by destroying throughput.
Questions to ask before choosing
- How often do two operations really update the same data concurrently?
- What is the business cost of a conflict?
- What is the business cost of making other operations wait?
- How long does the critical operation take?
- Can a failed optimistic update be retried safely?
- Should a human see the new state before deciding again?
- Do we monitor conflict rate, lock waits, and deadlocks?
- Is one record becoming a hotspot that needs a different design?
In the end
Optimistic and pessimistic locking solve the same basic problem with different economics.
Optimistic locking protects concurrency and makes conflicts explicit later. Pessimistic locking prevents conflicts earlier by making others wait. The right strategy is the one whose failure mode is cheaper for the actual business process.