# DDIA Ch. 8 — Transactions: a reading companion

**25,560 words, 5 top-level sections, 10 exercises.** The longest chapter in the
book and the one where the most people come away confidently wrong.

*The book's words appear in exactly two forms: blockquotes, and short spans in
quotation marks mid-sentence. Both are machine-checked verbatim against
the source epub by `tools/verify_quotes.py`. Everything else — read-weights,
misreads, cross-chapter threads — is my editorial judgment, and `[bracketed]`
words inside a quote are mine too. Trust the quotes; argue with the rest.*

## Before you start

This chapter assumes three things from earlier. **Ch. 6** — leaderless and
multi-leader replication, and last-write-wins conflict resolution; the
"Conflict resolution and replication" subsection here is unreadable without it.
**Ch. 7** — sharding, because cross-shard coordination is the whole cost story
of serial execution and distributed transactions. **Ch. 4** — the write-ahead
log, which is the mechanism under both single-node durability and the 2PC
commit point.

## The chapter in one claim

> Transactions are an abstraction layer that allows an application to pretend
> that certain concurrency problems and certain kinds of hardware and software
> faults don't exist. A large class of errors is reduced to a simple transaction
> abort, and the application just needs to try again.

Everything else is the price list for that pretending. The chapter's real
argument is that the abstraction **leaks at every isolation level below
serializable**, and it spends 25,000 words showing you exactly where.

## Section map

| Section | Words | Read | What it's for | Then run |
| --- | ---: | --- | --- | --- |
| **What Exactly Is a Transaction?** | 4,004 | | | |
| &nbsp;&nbsp;The Meaning of ACID | 2,008 | **Close** | The vocabulary the rest of the book uses. Note that C is the odd one out — it's the application's job, not the database's. | — |
| &nbsp;&nbsp;Single-Object and Multi-Object Operations | 1,683 | Skim | Motivating examples. One idea: multi-object writes need a way to say which writes belong together. | — |
| **Weak Isolation Levels** | 7,435 | | The core of the chapter. | |
| &nbsp;&nbsp;*(intro)* | 587 | **Close** | Short, and sets the stakes — race conditions at this level bankrupted a Bitcoin exchange. | — |
| &nbsp;&nbsp;Read Committed | 1,117 | **Close** | The two guarantees everything else is defined against. | [dirty-read-impossible](dirty-read-impossible.md) |
| &nbsp;&nbsp;Snapshot Isolation and Repeatable Read | 2,277 | **Close** | The densest pages in the chapter: MVCC, visibility rules, and the naming disaster. | [read-skew](read-skew.md), [mvcc-no-blocking](mvcc-no-blocking.md), [update-bloat-mvcc](update-bloat-mvcc.md) |
| &nbsp;&nbsp;Preventing Lost Updates | 1,608 | **Close** | A menu of five fixes. Know which ones your database does *for* you. | [lost-update](lost-update.md), [compare-and-set](compare-and-set.md) |
| &nbsp;&nbsp;Write Skew and Phantoms | 1,850 | **Close** | The hardest idea in the chapter, and the one interviews ask about. | [write-skew-doctors](write-skew-doctors.md), [phantom-write-skew](phantom-write-skew.md) |
| **Serializability** | 5,660 | | | |
| &nbsp;&nbsp;*(intro)* | 365 | **Close** | Names the three implementations. Read it as the section's table of contents. | — |
| &nbsp;&nbsp;Actual Serial Execution | 1,628 | Skim | Real but niche (VoltDB, Redis). Keep the *why it became viable* argument, drop the details. | — |
| &nbsp;&nbsp;Two-Phase Locking | 1,804 | **Close** → Ref | Close through "Predicate locks" and "Index-range locks"; the performance subsection is reference. | [deadlock-detection](deadlock-detection.md) |
| &nbsp;&nbsp;Serializable Snapshot Isolation | 1,866 | **Close** | The payoff of the chapter — how you get serializability without the 2PL tax. | — |
| **Distributed Transactions** | 4,986 | | | |
| &nbsp;&nbsp;*(intro)* + Two-Phase Commit | 2,261 | **Close** | The system of promises, and why the coordinator's disk is the commit point. | [prepared-transaction-locks](prepared-transaction-locks.md) |
| &nbsp;&nbsp;Distributed Transactions Across Different Systems | 1,855 | Skim | XA is a 1991 C API you probably won't touch. Do read "Holding locks while in doubt." | — |
| &nbsp;&nbsp;Database-Internal Distributed Transactions | 323 | **Close** | Tiny and important: why CockroachDB/Spanner escape XA's problems. | — |
| &nbsp;&nbsp;Exactly-Once Message Processing Revisited | 551 | **Close** | The most directly usable pattern in the chapter. | — |
| **Summary** | 3,475 | Ref | Table 8-1 is the single artifact worth memorizing. The prose recap is skippable if the exercises landed. | — |

## Load-bearing claims

**1. "ACID" tells you almost nothing.** The chapter demolishes its own title
concept early, and everything after depends on you having accepted this:

> Today, when a system claims to be "ACID compliant," it's unclear what
> guarantees you can actually expect. "ACID" has unfortunately become mostly a
> marketing term.

**2. Weak isolation is the default, not the exception.** The section opens with
real money lost to weak-isolation race conditions — a bankrupted Bitcoin
exchange, an investigation by financial auditors, corrupted customer data — and
then closes the escape hatch you'd reach for, which is "use a proper ACID
database":

> Even many popular relational database systems (which are usually considered
> ACID) use weak isolation, so they wouldn't necessarily have prevented these
> bugs from occurring.

That is the sentence that should make you check what isolation level your
production database is actually running.

**3. Write skew is the anomaly that only serializability closes.** Every other
race in the chapter has a cheaper fix; this one doesn't. Tested directly by
[write-skew-doctors](write-skew-doctors.md), where Postgres's REPEATABLE READ
lets both doctors leave:

> Automatically preventing write skew requires true serializable isolation

**4. The MVCC/2PL divide is one sentence.** Snapshot isolation's design
principle is that <q class="book">readers never block writers, and writers
never block readers</q> — and 2PL is precisely the negation of it. Confirm with
[mvcc-no-blocking](mvcc-no-blocking.md):

> In 2PL, writers don't just block other writers; they also block readers, and
> vice versa.

**5. SSI's trick is that its locks don't lock.** When a transaction writes, SSI
looks in the indexes for other transactions that recently *read* that data —
the same bookkeeping 2PL uses to take a write lock, but with the waiting taken
out:

> rather than blocking until the readers have committed, the lock acts as a
> tripwire; it simply notifies the transactions that the data they read may no
> longer be up-to-date.

The abort still happens, just at commit time instead of read time — which is
why long read-only transactions stay cheap under SSI.

**6. 2PC's failure mode is held locks, not lost data.** The reason distributed
transactions have the reputation they do — and what
[prepared-transaction-locks](prepared-transaction-locks.md) makes you watch
survive a full server restart:

> If the coordinator's log is entirely lost for some reason, those locks [the
> row locks every in-doubt participant took before voting yes] will be held
> forever—or at least until the situation is manually resolved by an
> administrator.

## Common misreads

**"Repeatable read means repeatable read."** It doesn't mean anything reliable.
In PostgreSQL it's snapshot isolation; in MySQL it's weaker than snapshot
isolation; in Db2 it's serializability. The book's verdict is blunt:

> nobody really knows what repeatable read isolation means

*If you read one thing closely in this chapter, make it this subsection.* Every
"but my database prevents that" argument dies here.

**"Atomicity protects me from concurrent writers."** It doesn't — that's
isolation. The A and the I get conflated constantly because "atomic" means
something different in multithreaded programming:

> in the context of ACID, atomicity is not about concurrency

The book even concedes the name is bad: <q class="book">Perhaps abortability
would have been a better term than atomicity</q>.

**"Snapshot isolation prevents lost updates, so I'm fine."** Sometimes — and
which "sometimes" is a per-database fact you have to look up. PostgreSQL's
repeatable read detects them; MySQL's does not:

> MySQL/InnoDB's repeatable read isolation level does not detect lost updates

[lost-update](lost-update.md) is worth running precisely because the answer
depends on the engine, not the standard.

**"Serializable is too slow to consider."** True of 2PL, and that reputation
outlived its cause by about fifteen years. SSI changed the trade:

> an algorithm called serializable snapshot isolation (SSI) provides full
> serializability with only a small performance penalty compared to snapshot
> isolation

**"2PL and 2PC are two halves of one thing."** They share nothing but a number.
The book puts a box in the middle of the chapter to say so — 2PL is
single-node isolation, 2PC is distributed atomic commit.

**"Exactly-once delivery requires distributed transactions."** The last section
quietly dismantles this, and it's the most practically useful paragraph in the
chapter:

> achieving exactly-once processing requires only transactions within the
> database—atomicity across database and message broker is not necessary for
> this use case [acknowledging a broker message exactly when the writes that
> processed it commit]

## Connects to

**Back:** Ch. 6 — lost updates reappear as LWW conflict resolution, and this
chapter's locks assume the single up-to-date copy that leaderless replication
denies you. Ch. 7 — cross-shard transactions are why serial execution stops
scaling.

**Forward:** Ch. 9 is the direct sequel — 3PC fails here because networks have
unbounded delay, which is exactly what Ch. 9 formalizes. Ch. 10 supplies the
fix this chapter defers: replace the single-node coordinator with consensus.
Note also that *serializability* (this chapter) and *linearizability* (Ch. 10)
are different guarantees that both get called "consistency"; the book flags the
overloading here but doesn't resolve it until Ch. 10. Ch. 12 revisits
exactly-once semantics in stream processing.
