ACID Transactions Simulator
A bank transfer: debit alice by 30, credit bob by 30. Run it step by step, optionally crash mid-transaction, and watch atomicity roll it back. Run a concurrent reader at different isolation levels to see what they see. The total balance never changes — that's consistency, in action.
| name | committed | staged |
|---|---|---|
| alice | 100 | — |
| bob | 50 | — |
Two accounts, alice and bob, each with a committed column (what's safely on disk) and a staged column (what the in-flight transaction has written but not yet committed). The buttons walk one transfer through its life: BEGIN, debit alice by 30, credit bob by 30, then COMMIT or ABORT. The transaction log tags every entry as "✓ durable" (survives a crash) or "○ mem" (gone the moment the power is). The two reader buttons simulate a second transaction peeking at the accounts mid-flight.
Start with the half-finished transfer: BEGIN, write alice, then hit Crash. On restart the staged value is wiped and alice still has 100 — atomicity discarded the partial work. Then run the same steps and press "Read at READ COMMITTED" after the debit but before the credit. The reader sees a total of 120: thirty units have vanished mid-transfer. Press the SERIALIZABLE button and the total is 150 again. Same data, same instant — the isolation level alone decides whether the money exists.
ACID — the four properties, one acronym
Coined by Theo Härder and Andreas Reuter, 1983.
ACID is the contract a database transaction makes with the application. It's an old contract — the acronym was coined in 1983 by Härder and Reuter — and it remains the bedrock of every relational database, plus a growing share of "NewSQL" systems (CockroachDB, Spanner, FoundationDB) that earned the right to use the term by implementing it properly.
Each letter describes a different property the application can rely on:
- Atomicity — the transaction is all-or-nothing. Either every write happens, or none. There's no "we debited Alice but the credit to Bob failed and now $30 has vanished" state. Implemented via the write-ahead log (see the WAL recovery sim): writes are staged in the log; only on COMMIT do they become visible.
- Consistency — the transaction respects all the database's constraints. Foreign keys point at real rows. Check constraints hold. Triggers fire correctly. If any constraint would be violated, the transaction aborts. (This is the most often misunderstood letter — it's about constraint enforcement, NOT about CAP-theorem-style consistency, which means something different.)
- Isolation — concurrent transactions don't see each other's in-progress work, as long as you ask for a strong-enough isolation level. SERIALIZABLE behaves as if the transactions ran one at a time in some order; weaker levels (READ COMMITTED, REPEATABLE READ) trade isolation for throughput, which is the entire content of the isolation-levels sim.
- Durability — once COMMIT returns successfully, the data survives any subsequent crash. Implemented via fsync to the write-ahead log: COMMIT doesn't return until the log entry has been written to non-volatile storage. Pull the power cord; restart; the committed data is still there.
Why some databases drop ACID — and what they get for it
Throughput, latency, simpler ops.
ACID is expensive. Atomicity requires the WAL to be written and fsynced before COMMIT can return — a disk round-trip per transaction. Isolation requires locks (or MVCC version chains), which serialise concurrent work and consume memory. Consistency requires constraint checks on every write.
"NoSQL" databases (Cassandra, DynamoDB, MongoDB pre-4.0, Riak) historically dropped some or all of these in exchange for horizontal scale and low latency. Their pitch: most application data doesn't need ACID. A like count on a social-media post can be eventually consistent. A view counter doesn't need constraint-checked consistency. A product-recommendation cache doesn't need durability beyond best-effort.
The pendulum has swung back somewhat. MongoDB added multi-document ACID transactions in 4.0 (2018). Cassandra added lightweight transactions for single-row ACID. CockroachDB and Spanner showed that distributed ACID is possible (if expensive) at scale. The rule of thumb today: use ACID for state that has invariants you can name; relax it deliberately for state where eventual consistency is acceptable.