Transactions and ACID
7 pages · ~5 min✓ Reviewed
Builds on Indexing and Storage. Next up: Concurrency Control.
Transactions and the ACID Mental Model
1. What a Transaction Is
- A transaction = a group of statements run as one all-or-nothing unit of work
- Money transfer = debit + credit, together or not at all
- Failure midway undoes everything already done
- BEGIN
- Debit Astatement 1
- Credit Bstatement 2
- COMMITor undo all
2. The Four Guarantees
| Guarantee | Detail | |
|---|---|---|
| Atomicity | All apply or none | Failure midway undoes all |
| Consistency | Valid state to valid state | PK, FK, CHECK, UNIQUE never violated |
| Isolation | Looks like one at a time | Only as far as the chosen level allows |
| Durability | Survives crash or power loss | After COMMIT returns, data is in the log on disk |
3. Durability Chain
- 1Write log
- 2Flush log to disk
- 3COMMIT returns
Isolation is a dial, not a guarantee of full serial behaviour: the level you choose decides what other transactions can interfere with.
Commit, Rollback and Savepoints in Practice
1. Core flow
- BEGINopen transaction
- Run statements
- COMMITmake permanent
- ROLLBACKdiscard all changes
- Transfer: both updates apply together, or neither
BEGIN; UPDATE accounts SET bal = bal - 100 WHERE id = 1; UPDATE accounts SET bal = bal + 100 WHERE id = 2; COMMIT;
debit + credit as one unit
2. Autocommit and savepoints
- Autocommit: each statement is its own transaction
BEGIN(START TRANSACTION) turns it off until COMMIT/ROLLBACKROLLBACK TO sp1undoes only work after the savepoint; transaction stays open
SAVEPOINT sp1;
-- more statements
ROLLBACK TO sp1;
COMMIT;work before sp1 is still committed
3. Gotchas
| MySQL | PostgreSQL | |
|---|---|---|
| DDL | implicit commit | transactional DDL |
An error aborts the whole transaction: every statement fails until you ROLLBACK.
Read Anomalies: Dirty, Non-Repeatable and Phantom
1. Three read anomalies
| Anomaly | What you see | Other transaction |
|---|---|---|
| Dirty read | uncommitted change, wrong if it rolls back | not committed yet |
| Non-repeatable read | same row, different value on re-read | committed an UPDATE |
| Phantom read | same range query, different set of rows | committed an INSERT or DELETE matching the predicate |
2. Lost update
- Both transactions read the same value, then both write
- One overwrite is silently lost
- Fix: lock the row with
SELECT ... FOR UPDATE, or use one atomicUPDATE
SELECT bal FROM accounts WHERE id = 1 FOR UPDATE; UPDATE accounts SET bal = bal + 1 WHERE id = 1;
either form works; the atomic UPDATE needs no prior read
3. Write skew
- Two transactions read overlapping data, update different rows
- Together they break an invariant: two doctors both go off-call
- Needs SERIALIZABLE or explicit locking
Lost update hits the same row: lock it or use an atomic UPDATE. Write skew hits different rows: only SERIALIZABLE or explicit locking stops it.
Isolation Levels Compared
1. The four levels
| Level | Dirty | Non-rep. | Phantom | Default |
|---|---|---|---|---|
| READ UNCOMMITTED | yes | yes | yes | rarely used |
| READ COMMITTED | no | yes | yes | PostgreSQL, Oracle, SQL Server |
| REPEATABLE READ | no | no | yes (standard) | MySQL InnoDB |
| SERIALIZABLE | no | no | no | none |
2. How each one behaves
- READ COMMITTED: each statement sees data committed before it started
- REPEATABLE READ: one snapshot from the first read
- InnoDB adds gap locks, blocking most phantoms
- SERIALIZABLE: outcome equals some serial order, paid in locks or aborts
- The app must retry serialization failures
3. Setting the level
- Set it per transaction; the order differs by database, and MySQL gives ERROR 1568 if it is wrong
BEGIN; SET TRANSACTION ISOLATION LEVEL REPEATABLE READ;
PostgreSQL: after BEGIN, before the first query
SET TRANSACTION ISOLATION LEVEL REPEATABLE READ; START TRANSACTION;
MySQL: before START TRANSACTION, applies to the next one
Higher isolation means less concurrency and more conflicts.
Write-Ahead Logging and Crash Recovery
1. The WAL Rule
- WAL rule: the log record is flushed before the data page it describes
- COMMIT needs only the log flush, a sequential write
- Data pages are written lazily later, so durability is cheap
- 1Write logchange record
- 2Flush logsequential
- 3Ack COMMITdurable
- 4Write pageslater
2. Steal / No-Force and Checkpoints
| Policy | Dirty page is written | So the log needs |
|---|---|---|
| Steal | before commit | undo |
| No-force | not forced at commit | redo |
- Checkpoint: flush dirty pages and record a log position
- Recovery replays only the log after it, so replay is bounded
3. ARIES Recovery: 3 Passes
- Analysisfind dirty pages, active txns
- Redoreplay logged changes
- Undoroll back uncommitted
Redo committed work, undo uncommitted work.
Transactions Cheat Sheet
1. ACID and Commands
- Atomicity: all or nothing
- Consistency: valid state to valid state
- Isolation: no interference
- Durability: survives a crash
BEGIN;
SET TRANSACTION ISOLATION LEVEL REPEATABLE READ;
SAVEPOINT x;
ROLLBACK TO x;
COMMIT; -- or ROLLBACK;PostgreSQL order: SET TRANSACTION right after BEGIN
- MySQL:
SET TRANSACTIONgoes beforeSTART TRANSACTION; after it, ERROR 1568
2. Isolation and Locks
| Level | Non-repeatable | Phantom |
|---|---|---|
| READ COMMITTED | allowed | allowed |
| REPEATABLE READ | prevented | allowed (standard) |
| SERIALIZABLE | prevented | prevented |
SELECT ... FOR UPDATElocks selected rows: stops lost updates- Keep transactions short: fewer lock waits and deadlocks
3. Durability Chain
- Write log
- Flush log
- Ack COMMIT
- Data pageswritten later
Redo committed work, undo uncommitted work.
Check yourself
PostgreSQL, default level. T1 reads a balance (100). T2 sets it to 50 and commits. T1 reads again. What does T1 see?
- 50, a non-repeatable read
- REPEATABLE READ would still show 100 (snapshot)
Two sessions each read bal (100), then write bal = 110 from the app. What is the final balance, and what is the fix?
- 110, so one +10 is lost (lost update)
- Use
UPDATE SET bal = bal + 10orSELECT ... FOR UPDATE
PostgreSQL: BEGIN; INSERT ok; INSERT violates UNIQUE; INSERT ok; COMMIT. What persists?
- Nothing
- The error aborts the transaction, and later statements fail until ROLLBACK
- COMMIT then acts as a ROLLBACK
COMMIT returned, then power failed before the data page reached disk. Is the change lost?
- No
- The log was flushed first (WAL)
- Recovery redoes the change from the log