ACID Properties

A bank must move 500fromAlice′saccounttoBob′saccount.Thisrequirestwowrites:debitAlice,creditBob.Ifthesystemcrashesafterthedebitbutbeforethecredit,500 from Alice's account to Bob's account. This requires two writes: debit Alice, credit Bob. If the system crashes after the debit but before the credit, 500 vanishes into thin air. Two such transfers might also run concurrently. If their reads and writes interleave carelessly, the bank's books can become permanently inconsistent. This can happen even with no crash at all. ACID properties are the contract a database management system offers. They ensure programmers never have to reason about these failure modes by hand. This problem is not exotic. It is the default hazard of any system where multiple operations must appear to happen "all at once." This holds whenever hardware, memory, and disks are shared with other work. Every serious data-management system must answer the same question. This includes a single-node relational database and a distributed ledger alike. What happens when a multi-step operation is interrupted? What happens when it runs alongside another one? What happens when the machine loses power mid-write? The Transaction Concept names the unit of work. ACID is the precise specification of what a database promises about that unit. The big picture is that ACID decomposes "correct behavior under failure and concurrency." It splits this into four independent, checkable guarantees. Atomicity means all-or-nothing execution. Consistency means invariants are preserved. Isolation means concurrent transactions don't corrupt each other's view of the world. Durability means committed work survives crashes. Each letter addresses a different threat. These are, respectively: a crash mid-transaction, a buggy or malicious update, a scheduler interleaving two transactions, and a power failure right after commit. Each is implemented by a different piece of database machinery. This article defines each property precisely. It shows the mechanisms real systems use to deliver them: logging, locking, recovery. It works through a full bank-transfer trace, including a simulated crash. It also previews how the deeper machinery actually implements these guarantees. This includes Write-Ahead Logging for durability/atomicity. It also includes Serializability and Schedules for isolation.

Key takeaways
  • ACID = Atomicity, Consistency, Isolation, Durability — four guarantees a DBMS gives every transaction.
  • Atomicity: a transaction's effects are all applied or none are, even if the system crashes midway.
  • Consistency: a transaction moves the database between states that satisfy its integrity constraints.
  • Isolation: concurrent transactions behave as if run one at a time, in some order.
  • Durability: once a transaction commits, its effects survive any subsequent crash.
  • Atomicity and durability are implemented mainly via logging and recovery; isolation via concurrency control (locking or timestamps).
The core insight

ACID turns "what if the system crashes or another transaction interferes" into a solved problem, so application code can simply say begin, do work, commit.

The idea

A transaction is a sequence of one or more database operations (reads and writes) that the application treats as a single logical unit — for example, "transfer $500 from Alice to Bob." The ACID properties are the guarantees the DBMS makes about how transactions behave, individually and in combination with each other and with failures.

Atomicity means a transaction is indivisible: either every one of its writes is applied to the database, or none are. There is no state in which the debit from Alice happened but the credit to Bob did not. Atomicity is what makes it safe to write multi-step logic without manually checking, after every crash, which steps completed.

Consistency means a transaction, run alone starting from a state that satisfies the database's integrity constraints (declared constraints like foreign keys and check constraints, plus any invariants the application relies on, such as "total money in the system is constant"), leaves the database in a state that again satisfies those constraints. Consistency is a joint responsibility: the DBMS enforces declared constraints automatically, but application logic must be written correctly for constraints that are not directly expressible in schema declarations, such as "the sum of all balances equals the sum of all deposits ever made."

Isolation means that even though many transactions may execute concurrently for performance, each transaction should behave as though it were the only one running. Formally, a concurrent execution (a schedule) should have the same effect as some serial (one-at-a-time) execution of the same transactions — this property is called <a class="wiki-link" href="/wiki/cs-db-serializability-schedules" data-track="wiki_article.body.wiki_link">serializability</a>. Isolation is what prevents one transaction's half-finished work from ever being visible to, or corrupted by, another.

Durability means that once a transaction commits — the DBMS has reported success to the application — its effects are permanent. Even a crash one instruction later, or a disk failure the next day, must not undo a committed transaction (subject to the assumption that the storage medium itself isn't destroyed). These four properties are logically independent axes, but the mechanisms that implement them overlap: the same Write-Ahead Logging infrastructure used for atomicity (undoing incomplete transactions) is also used for durability (redoing committed ones after a crash), while isolation is a separate concern handled by concurrency control.

How it works

Atomicity and durability: logging and recovery

The standard technique is write-ahead logging (WAL): before any change is made to the actual database, a log record describing the change is written to stable storage. The log records enough information to redo the change (if the transaction commits) or undo it (if the transaction aborts or the system crashes before commit). The essential rule, called the WAL rule, is: 1. Before a data page is written to disk, all log records describing changes to that page must already be on stable storage (write log first, ahead of data). 2. Before a transaction is considered committed, all its log records — including a special commit record — must be on stable storage. This ordering is what makes recovery possible after a crash: the log is a durable, ordered history of every intended change, so the recovery process can replay it to reconstruct exactly which transactions finished and which did not. ``` procedure COMMIT(T): write log record flush log to stable storage // durability boundary mark T as committed return success to caller procedure ABORT(T): for each log record of T, in reverse order: restore X to old_value // undo write log record flush log to stable storage procedure RECOVER(): // runs after a crash, on restart // Phase 1: analyze the log to find which transactions committed committed := {}, active := {} for each log record in the log, in order: if record is : committed.add(T); active.remove(T) if record is : active.remove(T) if record is : active.add(T) // Phase 2: redo all writes of committed transactions for each log record in the log, in order: if T in committed: write new to X // Phase 3: undo all writes of transactions that never committed for each log record in the log, in reverse order: if T in active: // never committed, never explicitly aborted write old to X ``` This "redo committed, undo uncommitted" scheme is what real systems (with further refinements such as checkpoints and the ARIES algorithm) implement; the full mechanics are the subject of Write-Ahead Logging. The key point for ACID is that atomicity (undo) and durability (redo) are two sides of the same log.

Isolation: concurrency control

Isolation is enforced by a concurrency-control protocol that regulates the interleaving of operations from different transactions. The two dominant families are:

  • Lock-based protocols, such as two-phase locking, in which a transaction must acquire a shared (read) or exclusive (write) lock on a data item before accessing it, and — in the "two-phase" discipline — releases no lock until it has acquired all the locks it will ever need.
  • Timestamp-ordering / multiversion protocols, in which transactions are ordered by timestamps and the system either enforces that ordering directly on reads/writes, or keeps multiple versions of each data item so readers never block writers (multiversion concurrency control, used by PostgreSQL, Oracle, and others).

``` procedure TWO_PHASE_LOCKING(T): growing_phase := true locks_held := {} procedure READ(X): if growing_phase: acquire shared-lock(X); locks_held.add(X) return value of X procedure WRITE(X, v): if growing_phase: acquire exclusive-lock(X); locks_held.add(X) X := v procedure COMMIT_OR_ABORT(): growing_phase := false // shrinking phase begins release all locks in locks_held ``` The isolation guarantee delivered is precisely: any schedule produced by a protocol satisfying two-phase locking is guaranteed conflict-serializable — equivalent in effect to some serial order of the transactions. This is the formal notion developed fully under Serializability and Schedules; here it suffices to know that isolation is achieved by restricting which interleavings are allowed, not by literally running transactions one at a time (which would be correct but far too slow). Real systems also expose weaker isolation levels — Read Uncommitted, Read Committed, Repeatable Read, Serializable — trading some isolation guarantees for concurrency and performance; "full" isolation (serializability) is the strongest and most expensive.

Consistency

Consistency is enforced partly automatically and partly by discipline:

  • The DBMS checks declared constraints (primary keys, foreign keys, `CHECK` constraints, `NOT NULL`) at the end of each transaction (or statement) and aborts the transaction if any is violated.
  • The application programmer is responsible for ensuring that, in isolation, each transaction's logic preserves invariants not captured by declared constraints.

Because atomicity and isolation are what make "checking constraints only at transaction boundaries" meaningful (intermediate, possibly-inconsistent states are never exposed to other transactions and never persist if the transaction aborts), consistency is often described as a consequence of the other three properties working correctly, combined with correct application logic.

Figure
The four ACID guarantees and their implementing mechanisms
Transaction: BEGIN → operations → COMMIT / ABORT BEGIN read(A); write(A); read(B); write(B) ... COMMIT Atomicity all-or-nothing threat: crash mid-transaction mechanism: write-ahead log (undo on abort) Consistency invariants preserved threat: buggy update, bad state mechanism: constraint checks + correct app logic Isolation no cross-talk threat: concurrent interleaving mechanism: locking / MVCC, serializability Durability commits survive crash threat: crash after commit mechanism: write-ahead log (redo on recovery) Atomicity & Durability share the log; Isolation is a separate concurrency-control concern.

Complexity & correctness

Atomicity / durability cost. Every write to a data item requires one additional sequential write to the log before (or, in practice, batched with) the corresponding data write. Because the log is append-only, log writes are sequential I/O, which is cheap relative to random-access data-page writes; typical systems amortize this cost by flushing the log in batches (group commit). The space overhead is one log record per write, each of size proportional to the changed data (or, with logical logging, proportional to the operation), so total log size is O(total writes)O(\text{total writes}) across the system's history until old records are discarded at a checkpoint.

Correctness of recovery. The WAL rule is the invariant that makes the redo/undo recovery procedure correct:

  • Claim: after `RECOVER()` completes, the database state is exactly the state that would result from applying every committed transaction's writes, in log order, to the pre-transaction state, with no trace of any transaction that never committed.
  • Argument: by the WAL rule, every log record for a transaction is durable before that transaction's commit record is durable, and every commit record is durable before the transaction is reported as committed. Hence, at any crash point, the log contains a prefix of true history that includes complete information for every transaction the outside world has been told committed. The analysis phase correctly partitions transactions into "committed" (has a commit record) and "never committed" (does not), because a transaction cannot be told it committed without its commit record being durable. Redo re-establishes every committed write (idempotent, since redoing an already-applied write is harmless if writes are applied in log order), and undo removes every write made by a transaction with no commit record, restoring the pre-transaction value. No transaction's effects are partially present in the final state, which is exactly atomicity plus durability.

Isolation cost and correctness. Two-phase locking's correctness argument: suppose two transactions TiT_i and TjT_j both hold their final lock release points tit_i and tjt_j respectively (end of growing phase). If TiT_i's lock point precedes TjT_j's, one can show by induction on conflicting operations that every conflicting pair of operations between TiT_i and TjT_j occurs in the order "TiT_i before TjT_j," which is precisely the condition for the schedule to be conflict-equivalent to the serial schedule Ti,TjT_i, T_j — this is the formal content covered under Serializability and Schedules. The cost is concurrency lost to blocking (a transaction may wait for locks) and the possibility of deadlock, requiring detection or prevention, typically O(1)O(1) amortized overhead per lock request plus periodic O(V+E)O(V+E) deadlock-detection graph traversals in systems that use detection.

Honest tradeoffs. Full serializability and full durability are the strongest and most expensive settings; virtually every production system offers weaker, faster alternatives — weaker isolation levels (Read Committed is the common default), asynchronous replication instead of synchronous durability, and eventual consistency in distributed systems (see the CAP-theorem tradeoff space) — because the ACID guarantees, while easy to reason about, are not free.

Worked example

Trace the bank transfer T1T_1: "transfer $500 from Alice (balance 1000) to Bob (balance 300)," alongside a concurrent transaction T2T_2: "read Alice's balance for a statement," with a crash inserted mid-way.

StepActionLog (stable storage)Alice (disk)Bob (disk)Notes
0initial state—1000300
1T1T_1: BEGIN``1000300
2T1T_1: read(A)1000300reads 1000
3T1T_1: A := A − 500`` (log flushed first)1000 (buffer updated, disk not yet)300WAL rule: log before data
4T2T_2: read(A)1000300Isolation (locking) blocks T2T_2 until T1T_1's exclusive lock on A releases — T2T_2 never sees the intermediate value 500
5T1T_1: read(B)300reads 300
6T1T_1: B := B + 500``300 (buffer)
7CRASHlog has ``, ``, `` — no commit record1000300disk untouched; buffers lost
8Restart: `RECOVER()` analysis phaseT1T_1 has no commit record → "active", not "committed"
9`RECOVER()` undo phaseundo T1T_1's writes: restore A=1000 (no-op, disk already 1000), restore B=300 (no-op)1000300atomicity preserved: it's as if T1T_1 never ran

Now replay the same scenario but let T1T_1 reach commit before the crash:

StepActionLogAliceBob
6′T1T_1: B := B + 500``1000300
7′T1T_1: COMMIT`` flushed before returning success1000300
8′CRASH (data pages never flushed)log has full history incl. commit1000300
9′`RECOVER()` analysisT1T_1 has commit record → "committed"
10′`RECOVER()` redo phasereplay `` then ``500800

The two traces show atomicity ("all T1T_1's writes or none") and durability ("committed effects survive a crash") as directly enforced by the log, and isolation (step 4) as enforced by locking preventing T2T_2 from ever observing the half-finished value A=500A = 500.

Common pitfalls & traps

PitfallWhy it happensFix
Flushing data pages before their log recordsAssuming "write order doesn't matter" for performanceEnforce the WAL rule strictly: log record must be durable before the corresponding data page
Confusing "consistency" with "isolation"Both sound like "nothing goes wrong," but consistency is about constraints, isolation about concurrent interferenceConsistency = single-transaction correctness w.r.t. invariants; isolation = correctness under concurrent execution
Treating weak isolation levels as if they were serializableRead Committed / Repeatable Read allow anomalies (dirty reads, non-repeatable reads, phantoms) that programmers forget aboutExplicitly choose isolation level per workload; use Serializable when correctness depends on it
Assuming durability means "written to disk," ignoring the OS/disk write-back cacheA disk can acknowledge a write before it is physically persisted, silently breaking durabilityUse `fsync`/equivalent flush guarantees and disks/controllers configured for correct write-barrier semantics
Forgetting that commit is not "instant"Believing an application-level "commit returned" implies the transaction survives a crash that happens a microsecond laterThe log flush for the commit record must complete before success is reported — that instant is the durability boundary
Ignoring deadlock in lock-based isolationTwo-phase locking guarantees serializability, not deadlock-freedomAdd deadlock detection (wait-for graph) or a prevention scheme (timeouts, wait-die/wound-wait)

Pioneers & history

Origins · 1 minJim Gray and how this was discovered
JG
Jim Gray
1944–2007 (disappeared at sea) · Turing Award laureate, IBM/Tandem/Microsoft, foundational work on transaction processing

Jim Gray coined and formalized the ACID acronym together with Andreas Reuter, building on his earlier work at IBM System R and Tandem Computers on transaction processing systems. His 1981 paper "The Transaction Concept: Virtues and Limitations" and the later book Transaction Processing: Concepts and Techniques (with Reuter, 1993) established the vocabulary — atomicity, consistency, isolation, durability — that every database system since has used to describe correctness under concurrency and failure. Gray also pioneered practical recovery algorithms and later worked on scalable data-intensive computing before his disappearance at sea in 2007.

History
1970
— Edgar F. Codd publishes the relational model, creating the need for well-defined transactional semantics over relations.
1976
— Jim Gray's group at IBM System R develops early two-phase locking and logging-based recovery techniques.
1981
— Jim Gray's paper formalizes "the transaction concept," precursor to the ACID terminology.
1983
— Theo Härder and Andreas Reuter coin the acronym ACID in their paper on transaction recovery principles.
1993
— Gray and Reuter's Transaction Processing: Concepts and Techniques becomes the standard reference, cementing ACID as the industry-wide vocabulary.

Where this matters

Every mainstream relational database — PostgreSQL, MySQL/InnoDB, Oracle, Microsoft SQL Server, SQLite — implements ACID transactions as its core correctness contract, using write-ahead logging (often the ARIES-style algorithm) for atomicity/durability and locking or multiversion concurrency control for isolation. Financial systems (core banking, payment processing, stock exchanges) depend directly on atomicity and durability to guarantee money is never created or destroyed and never lost after a confirmed transfer. Airline reservation systems and inventory management rely on isolation to prevent two customers from double-booking the same seat or the same last unit of stock. Modern "NewSQL" distributed databases (Google Spanner, CockroachDB, YugabyteDB) extend ACID guarantees across machines, using distributed logging and consensus protocols to preserve the same four properties at global scale, while many NoSQL systems deliberately relax one or more ACID guarantees (often isolation or the scope of atomicity) in exchange for higher availability and throughput — a tradeoff made explicit in the discussion of distributed consistency models and the CAP theorem. Understanding ACID precisely is also the prerequisite for understanding why Write-Ahead Logging and Serializability and Schedules are built the way they are: both are engineering answers to the guarantees defined here.

Ask the tutor: How does the ARIES recovery algorithm extend the simple redo/undo scheme shown here to handle checkpoints and partial rollbacks efficiently?

Is ACID the same thing as "the transaction concept"?

No. The transaction concept defines what a transaction is — a logical unit of work with a begin and an end (commit or abort) — while ACID specifies the guarantees the DBMS makes about how that unit behaves under concurrency and failure. You can define transactions without ACID (some systems intentionally offer weaker guarantees for performance), but the transaction concept is the prerequisite vocabulary ACID is built on: you cannot state "the transaction commits atomically" without first having a notion of what a transaction and a commit are.

Why is consistency often considered the "odd one out" among the four properties?

Atomicity, isolation, and durability are guarantees the DBMS can enforce mechanically through logging and concurrency control, independent of what the transaction's code actually does. Consistency, by contrast, depends partly on application-level correctness: the DBMS can only enforce the invariants it knows about (declared constraints like foreign keys), while invariants encoded only in the application's logic (e.g., "total money is conserved") are the programmer's responsibility. Consistency is therefore a joint guarantee, upheld correctly only if atomicity and isolation are also upheld and the transaction's own code is correct.

Does every database really provide full ACID guarantees by default?

No — many production systems default to weaker settings for performance. Relational databases commonly default to a weaker isolation level, such as Read Committed, rather than full Serializable isolation, because full isolation reduces concurrency. Many NoSQL and distributed systems relax durability (asynchronous replication) or isolation (eventual consistency) by design, trading strict ACID guarantees for higher availability and lower latency, a tradeoff often summarized by the CAP theorem in distributed systems.

What exactly does "durable" mean if a disk itself later fails?

Durability is defined relative to the failures the system is designed to tolerate — typically crashes and power loss, assuming the persistent storage medium itself survives. If the physical disk is destroyed (fire, mechanical failure) durability alone does not protect the data; that requires additional mechanisms such as replication across independent disks or machines, redundant log copies, or backups. In practice, "durable" in ACID means "survives a crash of the database process or machine," and stronger disaster-tolerance is layered on top via replication.

How are atomicity and durability related mechanically, even though they are conceptually different?

Both are implemented using the same write-ahead log. Atomicity requires the ability to undo a transaction's writes if it doesn't commit, and durability requires the ability to redo a transaction's writes if it did commit but the data pages weren't yet flushed before a crash. The log stores exactly the information needed for both operations — before-images for undo, after-images for redo — so a single recovery procedure (analyze, redo, undo) delivers both guarantees simultaneously, as detailed under Write-Ahead Logging.

Can isolation be achieved without locking?

Yes. Multiversion concurrency control (MVCC), used by PostgreSQL, Oracle, and others, keeps multiple versions of each data item and lets each transaction read a consistent snapshot as of its start time, so readers never block writers and writers never block readers. Timestamp-ordering protocols are another lock-free approach, ordering transactions by assigned timestamps and aborting transactions that violate the intended order. Both achieve the same formal goal as locking — a serializable (or snapshot-isolated) outcome — through different mechanisms, each with its own tradeoffs in abort rates and read/write contention.

Why does the article mention serializability if isolation is already defined here?

Isolation is the informal goal ("transactions shouldn't interfere"); serializability is its precise mathematical definition ("the concurrent schedule is equivalent to some serial order of the same transactions"). Stating isolation without serializability would leave "shouldn't interfere" dangerously vague and unverifiable. The formal theory of schedules, conflict-equivalence, and the proof that two-phase locking guarantees serializability is developed fully under Serializability and Schedules, which this article intentionally sets up but does not exhaust.

Before this

Where this leads