Consistency You Can Explain to the Business is the chapter that supplies the vocabulary the next three chapters spend. A guarantee is not a feeling about freshness; it is a list of specific anomalies the system promises cannot occur, and every anomaly not on that list is something your application code has to handle itself.
Key takeaways
- An isolation level is a named list of permitted anomalies. Read it as a permission list rather than a quality tier, because the useful question is what is still allowed to happen.
- Snapshot isolation avoids the three ANSI phenomena and is still not serialisable, which the 1995 critique proved by naming write skew, and write skew is the anomaly that bites real business rules.
- The retry is yours. PostgreSQL's documentation states that applications using the serialisable level must be prepared to retry transactions due to serialisation failures.
- Defaults differ between engines you might treat as interchangeable: PostgreSQL defaults to Read Committed, InnoDB defaults to Repeatable Read.
- A guarantee you cannot state in one sentence to a non-engineer is a guarantee you have not chosen. Write the sentence, in the first person, and let the sourced material sit underneath it.
Read this after Chapter 2, which decided where state lives and what a copy is allowed to lag by, and before Chapters 4, 5 and 6, all three of which spend this vocabulary. The data model chapter needs it to read what a key-value store refuses to promise, the boundary chapter needs it because a transaction scope is an isolation question first, and the caching chapter needs it because a staleness contract is a guarantee wearing different clothes.
Two engineers argue about a double-booking bug for an hour. One says the transaction is correct because it reads the current bookings and then writes only if the slot is free.
The other says the transaction is correct too, and that it ran twice concurrently, and both copies read a free slot. They are both right. The database was never asked to prevent that.
A guarantee is a list of things that cannot happen
Consistency talk goes wrong because the word is used for two different things: what a distributed system shows a reader, and what a database permits concurrent transactions to do to each other. Both matter. Both are lists.
The useful definition is negative. A guarantee is the set of anomalies the system promises will not occur, and everything outside that set is permitted and must be handled by you. So the question at a design review is never whether the system is consistent. It is which anomalies are still on the table.
That reframing has a practical benefit. An anomaly has a name, an example, and a business consequence, so it can be discussed with somebody who does not write SQL. A phrase like strong consistency cannot.
The named levels are permission lists, not quality tiers
The ANSI SQL levels are usually taught as a ladder from worse to better, which encourages teams to pick a rung by vibe. The 1995 critique took them apart properly.
Berenson, Bernstein, Gray, Melton, O'Neil and O'Neil published A Critique of ANSI SQL Isolation Levels as Microsoft Research technical report MSR-TR-95-51, and at SIGMOD, in June 1995. Their finding is that the three ANSI phenomena are ambiguously worded and fail to characterise several popular isolation levels. They add anomalies the standard omitted: dirty write, lost update, read skew and write skew.
They also define snapshot isolation, and this is the part that matters most for a working design. Snapshot isolation avoids all three ANSI phenomena and is still not serialisable. In their treatment it sits between Read Committed and Repeatable Read rather than above them.
That result is thirty-one years old. It is still the single most useful thing to know about isolation, because a level can look clean and let a specific class of bug through.
Write skew is the anomaly that survives a snapshot
Write skew deserves a worked example because it is the one that reaches production wearing the disguise of correct code.
Take an on-call rota with a rule that at least one engineer must be on shift. Two engineers each open a transaction to remove themselves. Each transaction reads the rota, sees the other person still on shift, concludes the rule is satisfied, and writes its own removal. Both commit. Neither transaction saw a conflicting write, because they wrote different rows.
The rule is now broken and no single transaction violated it. That is write skew, and snapshot isolation permits it because the check and the write touched disjoint data.
The same shape appears in inventory that goes negative, in two approvals that each assume the other reviewer exists, and in a balance rule enforced across two accounts. If your business rule is a constraint over a set of rows rather than over one row, you have a write skew exposure. Look for it deliberately.
What each level permits, and what your code owns
This table is the artifact worth lifting from the chapter. It maps levels to what remains permitted and to the work that therefore lands in your application.
| Level | Still permitted | What your application must own |
|---|---|---|
| Read Uncommitted | Dirty reads in the standard; PostgreSQL implements it as Read Committed | Nothing you should rely on. Do not design against this level |
| Read Committed | Non-repeatable reads, phantoms, lost update, read skew, write skew | Re-reading inside the transaction, explicit row locks, or moving the check into the write statement |
| Repeatable Read | In PostgreSQL, phantoms are prevented and serialisation anomalies remain; in InnoDB this is the default and reads use the first read's snapshot | Awareness that a consistent snapshot is not a lock, and an explicit locking read where a decision depends on other rows |
| Snapshot isolation | Write skew, per the 1995 critique | The invariant that spans rows, enforced by materialising the conflict or by escalating the level |
| Serializable | Nothing on the anomaly list | A retry loop, because the engine will abort transactions to preserve the guarantee |
Two rows in that table cause most production surprises. The Read Committed row, because it is PostgreSQL's default and most code was written as though it were stronger. And the Serializable row, because the guarantee is real and it is delivered by refusing work.
The retry belongs to your application
The most commonly skipped consequence of choosing a strong level is that it hands you an error to handle.
PostgreSQL's transaction isolation documentation is direct about this. It accepts all four standard levels but implements three, treating Read Uncommitted as Read Committed. Its Serializable level is implemented as serialisable snapshot isolation, raises SQLSTATE 40001 on a serialisation failure, and the documentation states that applications using this level must be prepared to retry transactions due to serialisation failures.
That sentence is a design requirement. A serialisable transaction is not a setting you flip. It is a setting plus a retry loop with a bounded attempt count, plus a decision about what the user sees when the retries run out. Chapter 8 handles the mechanics of bounding retries, and this is the first place the book needs them.
MySQL's 8.4 manual describes a different set of defaults for the same nominal ladder. InnoDB defaults to Repeatable Read, and a consistent read within a transaction reads the snapshot established by the first read. Read Committed takes a fresh snapshot for each statement and restricts gap locking. Serializable converts a plain SELECT into SELECT FOR SHARE when autocommit is off. Two engines, two defaults, same level names.
Naming where a store sits, so later chapters can use it
Beyond a single database, the vocabulary needs one more axis, because a replicated system answers reads from more than one place.
Abadi's PACELC formulation, published in IEEE Computer in February 2012, gives the naming. If there is a partition, does the system prefer availability or consistency, and else, in normal operation, does it prefer latency or consistency. His classification puts default Dynamo, Cassandra and Riak at PA/EL, VoltDB, H-Store, Megastore, BigTable and HBase at PC/EC, MongoDB at PA/EC and PNUTS at PC/EL.
Use those four letters as shorthand in your design document. They compress a paragraph of argument into a label that a reviewer can challenge, which is exactly what a design document is for. Chapter 4 leans on this directly when it reads what a store's own documentation refuses to promise.
Spanner is technically CP and effectively CA
There is one more thing worth taking from the literature, because it corrects the way CAP is usually deployed in arguments.
Brewer's paper on Spanner, TrueTime and the CAP theorem, published by Google on 14 February 2017, describes Spanner as technically CP and effectively CA: it chooses consistency and forfeits availability during a partition. Its measured availability is high enough that users design as though it were always available. The paper reports that geographically distributed Chubby cells average 99.99958 percent availability for outages of thirty seconds or more.
The more useful number is the breakdown of what actually caused unavailability. It reads 52.5 percent user, 13.3 percent bug, 12.1 percent cluster, 10.9 percent other, 7.6 percent network and 3.7 percent operator. Network is a small minority.
That distribution should change where you spend design effort. The partition you argue about in the CAP debate is not the thing most likely to make your system unavailable. Chapter 9 builds on this properly.
The sentence a non-engineer will accept
This is the part with no source, because it is a writing act rather than a fact. So it is judgement, and I will write it as mine.
A guarantee is only chosen when you can say it in one sentence, without jargon, naming who is affected and for how long. My template has three clauses: what is always true immediately, what may be briefly wrong, and how briefly. For instance: a booking is confirmed the moment the customer sees it and cannot be lost, while the manager's dashboard may be up to five seconds behind.
That sentence does several jobs at once. It tells the business what to promise customers, it tells support what is a bug and what is expected, and it gives you the reversal signal: if the dashboard is routinely thirty seconds behind, the guarantee is violated and the design has to change.
Write one sentence per read path. If you cannot, the design is not finished, and the gap is in the design rather than in your vocabulary.
The objection: nobody has ever complained
The strongest objection is empirical. The system has run for two years at Read Committed with no reported corruption, so the argument looks academic.
Two responses. The first is that write skew is silent by construction. Nothing logs it, no error is raised, and the damage shows up as a data quality complaint months later that nobody traces back to concurrency. Absence of reports is not evidence of absence.
The second is about cost timing. Choosing a level and writing the guarantee sentence costs an afternoon now. Discovering the exposure later costs an incident, a reconciliation script, and a migration of a running system, which is chapter 12's subject and the most expensive thing in this book. The asymmetry is the argument, not the theory.
Chapter summary
Consistency is best defined negatively. A guarantee is the list of anomalies a system promises cannot happen, everything outside that list is your application's problem, and the design question is therefore never whether the system is consistent but which anomalies remain permitted. The 1995 critique by Berenson, Bernstein, Gray, Melton, O'Neil and O'Neil showed the three ANSI phenomena are ambiguously worded, added dirty write, lost update, read skew and write skew, and defined snapshot isolation as a level that avoids the ANSI phenomena while still not being serialisable, sitting between Read Committed and Repeatable Read. Write skew is the practical consequence, and it appears wherever a rule is an invariant over a set of rows rather than over one row, as in an on-call rota where two transactions each remove a different person after each confirms the other is present. Choosing a strong level hands you work: PostgreSQL implements three of the four standard levels, treats Read Uncommitted as Read Committed, implements Serializable as serialisable snapshot isolation, and states that applications at that level must be prepared to retry after serialisation failures, while InnoDB defaults to Repeatable Read instead. Abadi's PACELC labels give a compact way to record where a replicated store sits, Brewer's 2017 Spanner paper shows network causing only 7.6 percent of that system's unavailability, and the chapter's decision is one guarantee sentence per read path with the staleness threshold that would reverse it.
Guarantees decided, the next decision is which store can answer the questions you actually ask, and what each one refuses to promise in the vocabulary this chapter just supplied. Chapter 4 is Choosing a Data Model You Can Live With.
Sources
- A Critique of ANSI SQL Isolation LevelsBerenson, Bernstein, Gray, Melton, O'Neil, O'Neil, MSR-TR-95-51 and SIGMOD 95 · 1995-06 · Research paper · verified
- PostgreSQL 18 documentation: Transaction IsolationPostgreSQL Global Development Group · 2026-07-29 · Official documentation · verified
- MySQL 8.4 Reference Manual: Transaction Isolation LevelsOracle · 2026-07-29 · Official documentation · verified
- Consistency Tradeoffs in Modern Distributed Database System DesignD. J. Abadi, IEEE Computer 45(2), 37-42 · 2012-02 · Research paper · verified
- Spanner, TrueTime and the CAP TheoremE. Brewer, Google · 2017-02-14 · Vendor engineering · verified