ACID in 2 minutes
ACID is what a relational engine guarantees for a transaction on a single node. The catch: most of its sharp edges live in how you use it — transaction scope, isolation level, and where the durability boundary actually sits.
A — Atomicity
A transaction is all-or-nothing. If any step fails or the server crashes mid-flight, every change inside the transaction is rolled back as if it never happened. The canonical example is a money transfer: the debit and credit either both happen, or neither does. On crash, the WAL replay on restart reverses incomplete transactions to keep this promise.
C — Consistency
Each transaction moves the database from one valid state to another, where “valid” means the constraints you declared: foreign keys, NOT NULL, CHECK, UNIQUE. No constraint, no consistency — the engine doesn’t know your business rules unless you wrote them down.
C is the weakest letter. Härder and Reuter, who coined ACID in 1983 (building on Jim Gray’s earlier transaction work), basically said the same — A + I + D plus your declared constraints is what C means in practice. The engine doesn’t add anything magical here. Don’t confuse it with CAP-consistency (linearizability across nodes); different concept entirely.
I — Isolation
Concurrent transactions shouldn’t step on each other. The SQL standard defines four levels — Read Uncommitted, Read Committed, Repeatable Read, Serializable — each preventing more anomalies (dirty reads, non-repeatable reads, phantom reads). The default is rarely as strong as people assume:
| Engine | Default isolation |
|---|---|
| PostgreSQL | Read Committed |
| MySQL / InnoDB | Repeatable Read |
| SQL Server | Read Committed |
| Oracle | Read Committed |
A concrete anomaly worth memorising: write skew. Two transactions read the same set, each decides its write is safe based on the other not having committed yet, both commit. Snapshot Isolation doesn’t catch it. The textbook example: two on-call doctors both go off-call simultaneously because each sees the other still on. Only Serializable prevents it.
Isolation has a real cost. Stricter = less concurrency. Most production apps run at Read Committed and reach for SELECT ... FOR UPDATE or advisory locks on the few critical paths.
D — Durability
Once COMMIT returns, the change survives — even an immediate power loss. Postgres guarantees this by appending the change to the Write-Ahead Log and fsync-ing before acknowledging.
Two caveats people get burned by:
synchronous_commit = offtrades durability for throughput — D is the letter being relaxed.COMMITreturns before the WAL is fsync’d, so a crash can lose a few hundred ms of acknowledged commits. A/I/C still hold; the contract you’re breaking is “onceCOMMITreturns, the change survives.”- Replication. A primary can ack
COMMITbefore the change reaches replicas. If the primary dies before replication catches up, you can lose committed transactions. Synchronous replication fixes this at the cost of latency.
ACID across common databases
Not every “transactional” database guarantees all four letters. Quick matrix:
| Database | A | C | I | D |
|---|---|---|---|---|
| PostgreSQL | ✓ | ✓ | ✓ | ✓ |
| MySQL / InnoDB | ✓ | ✓ | ✓ | ✓ |
| SQLite | ✓ | ✓ | ✓ | ✓ |
| SQL Server | ✓ | ✓ | ✓ | ✓ |
| Oracle | ✓ | ✓ | ✓ | ✓ |
| CockroachDB | ✓ | ✓ | ✓ | ✓ |
| Google Spanner | ✓ | ✓ | ✓ | ✓ |
| MongoDB | ✓ multi-doc since 4.0 | ✓ validators / unique only | ✓ | ✓ |
| DynamoDB | ✓ ≤100 items per tx | ✓ type / conditional only | ✓ | ✓ |
| Redis | ✗ MULTI/EXEC has no rollback | ✗ no schema | ✓ single-threaded | ✓ requires AOF/RDB |
| Cassandra | ✗ LWT for single-key CAS | ✗ | ✗ | ✓ |
What ACID does not give you
- Race-condition prevention without the correct isolation level or explicit locks.
- Distributed transactions across services. Single node only — for cross-service work you need 2PC (rare, slow, blocking on coordinator failure) or Sagas (eventual consistency with compensating transactions).
- Idempotency for retried operations — that’s an application concern (idempotency keys, request fingerprints).
- Protection from your own bugs. The DB will happily commit garbage if your application code or constraints don’t catch it.
TL;DR: ACID is a single-node contract about what survives a crash. Distributed correctness, race conditions, and business rules are still on you.