Postgres, default READ COMMITTED. Two requests run this at the same moment for the last seat (seats_left = 1). The app computes the new value itself.
BEGIN;
SELECT seats_left FROM events WHERE id = 7;
-- app: if seats_left > 0
UPDATE events SET seats_left = 0 WHERE id = 7;
INSERT INTO tickets ...;
COMMIT;What happens?
Show answer
Answer
A transaction does not lock rows it only reads. At READ COMMITTED both SELECTs see 1, both pass the check, and the second UPDATE waits for the first, then writes 0 again: two tickets for one seat.
Atomicity means all or nothing on failure, not mutual exclusion. Serialization errors only happen at REPEATABLE READ or SERIALIZABLE. Postgres never checks app-side logic at READ COMMITTED.
Source: Hello Interview: Dealing with Contention, PostgreSQL Documentation: Transaction Isolation