Books Deep-Read · DDIA · Chapter 7

Transactions: shielding apps from concurrency and crashes

Designing Data-Intensive Applications · Ch 7 · Martin Kleppmann · 2017

中文 →

What's this chapter about?

You transfer money to a friend: your balance drops by 100, theirs hasn't gone up yet — and at that instant the data center loses power. Where did the money go? DDIA Chapter 7 is about the transaction, the database's answer: it guarantees that a group of operations either all happen or none of them do, never stopping halfway. The chapter also reveals that many databases' claimed "safety" is weaker than you'd think.

An analogy

A transaction is like packing for a move: you seal a room's worth of stuff into one box. It either arrives intact at the new place (commit), or something goes wrong en route and it's returned untouched to the old place (abort) — never "the table arrived but the chairs got lost on the way." The database seals "subtract from A" and "add to B" into the same box: they succeed together or fail together.

Why the old world is hard

The hard part isn't one person slowly editing data — it's many people editing at once. Two people grabbing the last ticket, both adding a line to the same wiki page, both deducting from the same account balance. If the database doesn't step in, one person's change gets silently overwritten, or you read a mix of half-old, half-new data — a garbled total. Add machines that can crash anytime, and chaos is the default.

The core intuition

How does the database keep everyone from clashing? The mainstream trick is to hand each transaction a "photo of this moment" — your operation sees the world exactly as it was when you began, invisible to others' later changes, so nothing scrambles it (this is a snapshot). When you say "commit," the database double-checks: did anything I read get changed in the meantime? If so, you redo it. Everyone reads their own photo, and we reconcile at commit — that's the skeleton of modern database concurrency.

A strange case first: two doctors both take leave

A hospital requires at least 2 doctors on call. Right now exactly 2 are on duty, and both want to take leave. They click "request leave" at nearly the same time: Dr. Li glances — "there are 2 of us, I can go" — and so does Dr. Wang — "there are 2, I can go." So both leave, and the on-call room is empty. Each looked fine alone; together they broke the rule. This "you read yours, I read mine, and together it goes wrong" trap (called write skew) is exactly what many supposedly-safe databases fail to catch — and this chapter teaches you to spot it.

How to choose

The database turns "safety" into an adjustable dial (called the isolation level): loosest is fast but prone to the messes above; tightest (called serializable, which behaves as if "everyone queues up one at a time") is safest but either slow or full of retries. The catch: names lie. Some databases label the dial "serializable" when it's really only turned to the middle. So don't trust the name — check which traps it actually blocks.

Remember this one line

A transaction = a box that's "all-or-nothing," shielding you from two kinds of chaos: concurrent clashes and mid-flight crashes. But "safety" is an adjustable dial whose label is often inflated — judge it by the traps it truly blocks, not the tier it claims.

One honest cost: turning the dial all the way up (true serializability) either forces transactions into a single slow queue, or makes them "collide and retry" under high concurrency — safety is never free.

Want the actual mechanics — ACID, isolation levels, MVCC snapshots, two-phase locking? → Switch to the Deep version