Understand Atomicity, Consistency, Isolation, and Durability — the four guarantees that make database transactions reliable.
Published April 1, 2025
ACID is an acronym for the four properties that guarantee database transactions are processed reliably. Every serious database interview starts here.
"All or nothing"
A transaction is treated as a single unit. Either all operations succeed, or none of them are applied. If a failure occurs mid-transaction, the database rolls back to its previous state.
-- Transfer $100 from Alice to Bob
BEGIN TRANSACTION;
UPDATE accounts SET balance = balance - 100 WHERE name = 'Alice';
UPDATE accounts SET balance = balance + 100 WHERE name = 'Bob';
COMMIT; -- Both succeed, or neither applies
If the system crashes after the first UPDATE but before the second, the rollback ensures Alice's money is returned.
"Data is always valid"
A transaction moves the database from one valid state to another. All integrity constraints (foreign keys, unique constraints, check constraints) must hold before and after the transaction.
-- Consistency: balance cannot go negative
ALTER TABLE accounts ADD CONSTRAINT chk_balance CHECK (balance >= 0);
If Alice only has $50 and you try to debit $100, the constraint prevents the transaction from completing — consistency is maintained.
"Concurrent transactions don't interfere"
Concurrently executing transactions behave as if they were executed serially. The intermediate state of a transaction is invisible to others.
Isolation levels (weakest to strongest):
| Level | Dirty Read | Non-Repeatable Read | Phantom Read |
|---|---|---|---|
| READ UNCOMMITTED | Yes | Yes | Yes |
| READ COMMITTED | No | Yes | Yes |
| REPEATABLE READ | No | No | Yes |
| SERIALIZABLE | No | No | No |
-- Set isolation level
SET TRANSACTION ISOLATION LEVEL REPEATABLE READ;
BEGIN TRANSACTION;
SELECT balance FROM accounts WHERE name = 'Alice'; -- reads 500
-- Another transaction cannot change Alice's balance until this commits
SELECT balance FROM accounts WHERE name = 'Alice'; -- still reads 500
COMMIT;
"Committed data survives failures"
Once a transaction is committed, it persists permanently — even if the system crashes immediately after. Databases achieve this through write-ahead logging (WAL): changes are written to a durable log before being applied to data files.
PostgreSQL, MySQL InnoDB, and MongoDB all use MVCC. Instead of locking rows for reads, they keep multiple versions of each row. Readers see a consistent snapshot; writers create new versions.
Transaction T1 (reads at time=10): Transaction T2 (writes at time=12):
SELECT balance → sees version@t=10 (500) UPDATE balance SET balance=400
→ creates new version@t=12 (400)
SELECT balance → still sees @t=10 (500) COMMIT
← T1 is unaffected!
COMMIT
fsync=off in PostgreSQL is faster but violates durability. Mention this trade-off.