Backend & Data
ACID transactions and isolation levels
Wrap some database operations in a transaction and you're leaning on a four-letter promise: ACID. Atomicity, Consistency, Isolation, Durability. Three of them are intuitive. The fourth — Isolation — is where the subtle, expensive bugs live, because it governs what happens when two transactions touch the same data at the same time.
The four letters
- Atomicity — all of it happens, or none of it does. Transfer money and the debit succeeds but the credit fails? The whole thing rolls back. No half-transfers.
- Consistency — the transaction moves the database from one valid state to another; rules and constraints hold before and after.
- Isolation — concurrent transactions don't step on each other; each behaves as if it ran alone.
- Durability — once committed, it survives — even if the server loses power a second later.
Why isolation is the hard one
Atomicity and durability are mostly the database's job. Isolation is where you get to choose how careful to be — and cutting corners for speed is how the classic anomalies sneak in. The canonical one is the lost update: two transactions read the same value, both modify it, and the second write silently erases the first.
Isolation levels — the safety/speed dial
Databases let you pick how strict isolation is, trading correctness against concurrency:
- Read Uncommitted — can even read another transaction's uncommitted, soon-to-be-rolled-back changes (a "dirty read"). Fast, dangerous, rarely wanted.
- Read Committed — only see committed data. A common default; still allows some anomalies.
- Repeatable Read — a row you read won't change under you mid-transaction.
- Serializable — the gold standard: transactions behave as if run one at a time, in some order. No anomalies — at the cost of more locking/retries.
A transaction promises all-or-nothing, and — if you ask for enough isolation — that concurrent transactions won't corrupt each other. Weaker isolation is faster but lets two correct programs quietly lose each other's writes.
What to actually do
For anything where being wrong costs real money — balances, inventory, counters — use strong isolation, or make the update atomic (UPDATE … SET balance = balance + 20 instead of read-modify-write in your app). It's the database-level sibling of idempotency: both are about staying correct when things happen concurrently or more than once. And it connects to CAP — strong guarantees cost availability under load and partitions. Know which anomalies your app can't tolerate, and buy exactly enough isolation to prevent them.