Anything committed between your read and your write is erased
T2 adds 20 and commits first. T1 writes 130 from its stale read of 100. Slow calls, retries and people at forms widen it.
One phone, two buyers
Bad: Wrap it in a transaction
Nobody waits between statements. Both buyers read 1 and get confirmed.
Good: Check inside the UPDATE
stock = stock - 1 WHERE stock >= 1 runs on the newest row.
Three honest ways to run the board
- Write the change, not the total → atomic UPDATE
- Hold the marker → lock the row with FOR UPDATE
- Check before you wipe → compare-and-set on a version
Sold out. Your guarded UPDATE matched 0 rows, and the driver raised no error.
The catch
Ignore the row count and you still confirm the order. Turn UPDATE 0 into “sold out”.
No transaction spans minutes of typing, so the version travels
Send the version as an ETag. Arjun’s stale save carries If-Match v7 and gets 412, instead of quietly reverting Priya’s P1.
Which fix? Walk down until the first “yes”.
The isolation level appears only at the bottom. Fix the write itself first.
Atomic balance + 200 fixed the race. Then a timeout retried the credit.
Deltas aren’t idempotent
The retry credits ₹200 twice. Pair every delta with an idempotency key.
Remember
Say where the arithmetic runs. Atomic UPDATE for sums, FOR UPDATE for app logic, a version for edits across requests.