ACID transactions
A transaction groups a set of reads and writes so the database treats them as one indivisible operation. ACID names the four properties that make this grouping dependable: atomicity, consistency, isolation, and durability. Jim Gray's 1981 paper The Transaction Concept named atomicity, consistency, and durability and worked out how a system delivers them. Theo Härder and Andreas Reuter added isolation and coined the acronym in their 1983 survey Principles of Transaction-Oriented Database Recovery.
These four properties, atomicity, consistency, isolation, and durability (ACID), describe the major highlights of the transaction paradigm, which has influenced many aspects of development in database systems. We therefore consider the question of whether the transaction is supported by a particular system to be the ACID test of the system's quality.
The four properties answer four different questions, and a database delivers each through different machinery. Reading them as a single bundle hides where each guarantee comes from and where each one breaks.
Atomicity makes a group of operations all-or-nothing
A transaction commits as a whole or aborts as a whole. A partial result never reaches durable storage. If a transfer debits one account and the system fails before it credits the other, atomicity rolls the debit back, so no state survives where the money left one account without arriving at the other. The database reaches this through a write-ahead log: it records the intended change before applying it, so recovery either replays a committed transaction or undoes an incomplete one. The unit of failure becomes the transaction, not the individual statement.
Gray's 1981 definition states it plainly. A transaction is "a transformation of state which has the properties of atomicity (all or nothing), durability (effects survive failures) and consistency (a correct transformation)." Isolation is absent from that list. Gray named three properties. Härder and Reuter added the fourth two years later.
Consistency in ACID is the application's invariant, not a database mechanism
Consistency in ACID means a transaction moves the database from one valid state to another. Valid covers declared constraints the engine checks (foreign keys, uniqueness, column types) and application rules the engine never sees (an inventory count that stays non-negative, a ledger that balances). The engine enforces the constraints you declare. The rest depends on the transaction being written correctly. Gray framed consistency as the transaction obeying "legal protocols," and Härder and Reuter tied it to outcome: a database is consistent when "it contains the results of successful transactions."
Consistency differs from the other three in a way worth naming. Atomicity, isolation, and durability are guarantees the database delivers on its own. Consistency is a contract between the database and the code you write. The database supplies the other three so that a correct transaction preserves your invariants. Whether the transaction is correct stays your responsibility.
Isolation runs on a spectrum from serializable down to read uncommitted
Concurrent transactions interfere. One reads a value another is partway through changing. One re-reads a row and finds it altered. One scans a range and a second scan returns rows that appeared in between. Serializable isolation removes all of this: the result matches some order in which the transactions ran one at a time. Serializable is the strongest guarantee and the most expensive, because the database holds more locks for longer, or aborts and retries more transactions, to maintain that appearance.
Weaker levels trade some of the guarantee for throughput. The ANSI SQL-92 standard defines four levels by the read anomalies each one forbids. The 1995 paper A Critique of ANSI SQL Isolation Levels catalogs them: the levels are "(1) READ UNCOMMITTED, (2) READ COMMITTED, (3) REPEATABLE READ, (4) SERIALIZABLE," separated by three phenomena, "Dirty Read, Non-repeatable Read, and Phantom."
| Isolation level | Dirty read | Non-repeatable read | Phantom |
|---|---|---|---|
| Read uncommitted | permitted | permitted | permitted |
| Read committed | prevented | permitted | permitted |
| Repeatable read | prevented | prevented | permitted |
| Serializable | prevented | prevented | prevented |
A dirty read returns a value another transaction wrote and has not committed. A non-repeatable read returns two different values for the same row inside one transaction. A phantom appears when a repeated range query picks up a row that a concurrent insert added. Each step down the table forbids one more phenomenon and pays for it in contention.
The level you run is rarely serializable, and its name rarely tells you the guarantee
Most engines default below serializable. PostgreSQL defaults to Read Committed. MySQL's InnoDB defaults to Repeatable Read. A transaction inherits the anomalies its level permits unless you raise the level for that transaction. The choice belongs to the operation. A monthly report tolerates a non-repeatable read and wants to avoid blocking writers. A balance check before a withdrawal does not.
The label compounds the problem, because the same level name denotes different guarantees across engines. The 1995 critique introduced snapshot isolation, "a multiversion concurrency control mechanism... that avoids the ANSI SQL phenomena, but is not serializable." Each transaction reads from a snapshot taken at its start, which blocks dirty reads, non-repeatable reads, and phantoms. Two transactions reading the same snapshot and updating different rows still commit a combined state neither would reach alone. This anomaly is write skew. PostgreSQL's Repeatable Read is snapshot isolation, and its own documentation states the level "prevents all of the phenomena described in Table 13.1 except for serialization anomalies." InnoDB's Repeatable Read also reads from a consistent snapshot established by the first read. Two engines, one level name, neither serializable, and a guarantee you confirm by reading the engine's documentation rather than the level's label.
Durability defines what a commit promises to survive
Once a transaction commits, its effects persist through failures. The promise sounds absolute and hides a spectrum. Durable against a process crash means the change reached the operating system. Durable against a power loss means the change reached the disk, through an fsync the database waited on before acknowledging the commit. Durable against the loss of a machine means the change reached replicas on other machines. Each step adds latency to the commit. Group commit recovers some of it by batching the fsync across several transactions, trading a little commit latency for throughput. "Committed" is precise only once you name the failure it survives.
The four properties decompose under distribution
On a single node, a write-ahead log and a concurrency-control scheme, locking or multiversioning, deliver all four properties together. Spread the data across machines and each property turns into its own problem. Atomicity across nodes needs an atomic commit protocol, so every participant commits or every participant aborts. Two-phase commit is the standard answer, and it stalls when the coordinator fails partway through. Durability across machines needs replication, which raises the consistency-and-latency question that PACELC frames. Isolation across shards needs concurrency control that spans nodes, which is why globally serializable distributed transactions stay rare and costly. ACID on one machine approaches free once the engine implements it. ACID across machines is a cost you pay deliberately.
Using ACID in a design
ACID is four guarantees, not one switch. Name them separately. State which isolation level each operation runs at and which anomalies that level permits on your engine. State what a commit has to survive, and confirm the database waits for that durability before it acknowledges. Treat atomicity that spans services or shards as a distributed-commit problem with its own failure modes, not as a property you get for free. The transaction boundary is a design decision, and drawing it well starts with knowing which of the four properties each operation needs.
Sources
- Jim Gray, The Transaction Concept: Virtues and Limitations, VLDB 1981. The transaction concept and the original statement of atomicity, consistency, and durability.
- Theo Härder and Andreas Reuter, Principles of Transaction-Oriented Database Recovery, ACM Computing Surveys 15(4), 1983. The survey that added isolation and coined ACID.
- Hal Berenson, Phil Bernstein, Jim Gray, Jim Melton, Elizabeth O'Neil, and Patrick O'Neil, A Critique of ANSI SQL Isolation Levels, ACM SIGMOD 1995. The isolation levels, the phenomena that separate them, and the definition of snapshot isolation.
- PostgreSQL, Transaction Isolation. Read Committed as the default, and Repeatable Read implemented as snapshot isolation.
- MySQL, InnoDB Transaction Isolation Levels. Repeatable Read as the InnoDB default.