Serial execution
One thread per partition. Every txn is a stored procedure that runs to completion, no interactive round-trips.
Chapter 07 · Transactions
Two people booked the same seat. And two on-call doctors both went off duty.
A transaction is a promise: all-or-nothing, isolated from the neighbors. Every weakening of that promise is a race waiting to happen.
ACID: atomic · consistent · isolated · durable. This chapter is the I.
Three acts: 1. races 2. snapshots 3. serialize
Same data, two clients, wrong answer.
Every anomaly is a promise the database didn't make. Isolation levels are the rungs of stronger promises.
The isolation ladder each row lists what that level newly prevents. protections are cumulative up the ladder. Read Committed dirty read · dirty write Snapshot Iso non-repeatable read · lost updates (concurrent write conflicts)* Serializable write skew · phantoms† * Lost-update detection is implementation-dependent. PostgreSQL (40001), SQL Server (3960), and Oracle (ORA-08177) abort the later writer on a same-row conflict. MySQL/InnoDB's snapshot covers reads only, not writes, so read-modify-write silently loses updates unless you SELECT ... FOR UPDATE. † SI blocks phantom reads via snapshots. But write skew is a separate anomaly, and snapshots alone can't catch it (the doctors above). Vendor names for SI: PostgreSQL → REPEATABLE READ · SQL Server → SNAPSHOT · Oracle → SERIALIZABLE (SI-based; write skew still possible).
Reads the past reliably. Cannot stop two futures from colliding.
Takeaway
Snapshot isolation blocks nearly every race. Write skew is the exception, and it is the whole reason Act 3 exists.
One thread per partition. Every txn is a stored procedure that runs to completion, no interactive round-trips.
Grab a shared lock on read, upgrade to exclusive on write. Hold until commit.
Run at SI. Track read-write dependencies. Abort losers at commit.
PostgreSQL 9.1+ defaults to SSI. It is the modern answer.
── Reference ──
Six anomalies · three sources of confusion · five things to remember.
| # | Anomaly | Definition | Example | First level that prevents it | Mechanism |
|---|---|---|---|---|---|
| 1 | Dirty read | Reading another txn's uncommitted write. | A reader sees balance=600 mid-transfer; the writer aborts, leaving a ghost value. | Read Committed | Only committed row versions visible. |
| 2 | Dirty write | Overwriting another txn's uncommitted write. | Two txns update listing + invoice; interleave sells to Alice, invoices Bob. | Read Committed | Row-level write locks held until commit. |
| 3 | Read skew | Two reads in one txn see different committed states. | Read acc1=$500 before transfer, acc2=$400 after: $900 sum that never existed. | Snapshot Iso | One snapshot per txn, not per statement. |
| 4 | Lost update | Two RMW cycles on the same row; later write overwrites earlier. | Both read counter=42, both write 43: one +1 lost. | Snapshot Iso* | First-committer-wins: abort with 40001 / 3960 / ORA-08177. |
| 5 | Write skew | Two txns read a shared premise, write disjoint rows; combined result violates invariant. | Both doctors see count=2, each removes themselves: 0 on call. | Serializable | SSI tracks read→write deps, aborts one. |
| 6 | Phantom | A row matching a predicate appears or disappears due to a concurrent write. | Check "slot free" returns empty, insert; concurrent insert wins the slot. | Read-side: SI. Write-decision: Serializable. | SSI read-write dependency tracking. |
* At each engine's SI level: PostgreSQL REPEATABLE READ (40001), SQL Server SNAPSHOT (3960), and Oracle SERIALIZABLE (ORA-08177) abort the conflicting writer. MySQL/InnoDB REPEATABLE READ silently loses updates; use SELECT ... FOR UPDATE or an atomic UPDATE.
| Question | Lost update | Write skew | Phantom-driven skew |
|---|---|---|---|
| Both txns write the same row? | Yes | No; disjoint | No; one writes a row the other's query would have matched |
| What's shared? | The row itself | A premise both read | A predicate |
| Does the conflicting row exist at read time? | Yes | Yes | No. The defining feature. |
| Can SI catch it? | Yes (same-row w-w) | No | No |
| Cheapest fix | Atomic UPDATE or FOR UPDATE | Serializable, or materialize the conflict | UNIQUE / exclusion constraint if expressible; else Serializable |
Dirty read/write → touching uncommitted data.
Read skew → my reads disagree with each other.
Lost update → our writes collide on one row.
Write skew → our writes don't collide, but our premises do.
Phantom → the collision is with a row that didn't exist yet.