Backend Development › Transactions & Concurrency Control
Lost Update
Two writers overwriting each other's changes.
Also known as: lost update, lost updates, concurrent update
A lost update happens when two transactions read the same value, both modify it, and both write back — so the second write overwrites the first, and one update is silently lost. The classic case is a counter.
T1: read 10 → compute 11
T2: read 10 → compute 11
T1: write 11
T2: write 11 ← T1's update is lost; correct value was 12
Both transactions were internally correct; the problem is the gap between the read and the write, where the other transaction slipped in (see read-modify-write).
There are three standard fixes:
- Atomic update — do it in one statement (
SET x = x + 1), so there’s no gap (see atomic update). - Pessimistic locking — lock the row before reading (
SELECT ... FOR UPDATE), so others wait. - Optimistic locking — include a version (or the old value) in the
WHERE, and retry if no row was updated, detecting that someone changed it.
UPDATE items SET qty = qty - 1 WHERE id = 7 AND qty >= 1; -- atomic
UPDATE items SET qty = 8, version = version + 1 WHERE id = 7 AND version = 3; -- optimistic
The classic mistakes:
- Assuming a transaction prevents it. A transaction alone doesn’t stop lost updates unless you lock the row or use a suitable isolation level. The read-modify-write inside each transaction still races.
- Reading then writing in two statements by default. This is the default shape in a lot of code and the reason lost updates are so common. Prefer the single-statement form.
- Optimistic locked but never retried. If the
WHERE version = ?matches nothing, the update changed nothing — you must detect that and retry, or the change silently vanishes. - Locking too broadly. Pessimistic locking a whole table (or many rows) serialises everything; lock the specific row you need.
- Forgetting inventory-style guards. Decrementing stock without a
WHERE qty >= nguard lets stock go negative under concurrency.
How to avoid it: for counters and simple arithmetic, an atomic update; for read-decide-write logic, optimistic locking with retry or a targeted FOR UPDATE lock. Recognise the read-modify-write pattern and treat it as a hazard. See transactions and isolation levels.