|$ curl https://forge-ai.dev/api/markdown?path=docs/databases/transactions
$cat docs/transactions-&-acid.md
updated Recently·30 min read·published

Transactions & ACID

DatabasesIntermediate to Advanced🎯Free Tools
Introduction

A database transaction is a logical unit of work that groups multiple operations into a single atomic unit. Either all operations succeed (commit) or none do (rollback). Transactions are the foundation of data integrity in relational databases.

ACID Properties
PropertyDescriptionExample
AtomicityAll operations succeed or all failTransfer debit + credit = both or neither
ConsistencyDatabase moves from one valid state to anotherForeign keys always reference existing rows
IsolationConcurrent transactions don't interfereTwo transfers on same account don't double-spend
DurabilityCommitted data survives crashesWAL ensures crash recovery
acid.sql
SQL
1-- Basic transaction: transfer money between accounts
2BEGIN;
3
4UPDATE accounts SET balance = balance - 100 WHERE id = 1;
5UPDATE accounts SET balance = balance + 100 WHERE id = 2;
6
7-- Verify the transfer is valid
8DO $$
9BEGIN
10 IF (SELECT balance FROM accounts WHERE id = 1) < 0 THEN
11 RAISE EXCEPTION 'Insufficient funds';
12 END IF;
13END $$;
14
15COMMIT;
16-- If any error occurs, PostgreSQL auto-rolls back the transaction
17
18-- Explicit rollback on error
19BEGIN;
20UPDATE accounts SET balance = balance - 100 WHERE id = 1;
21-- Oops, wrong account
22ROLLBACK; -- Undo everything in this transaction
Isolation Levels
LevelDirty ReadNon-RepeatablePhantomPerformance
Read UncommittedYesYesYesFastest
Read CommittedNoYesYesFast (PostgreSQL default)
Repeatable ReadNoNoYesModerate (MySQL default)
SerializableNoNoNoSlowest (full isolation)
isolation.sql
SQL
1-- Set isolation level for a transaction
2BEGIN ISOLATION LEVEL READ COMMITTED;
3-- Default in PostgreSQL; most common choice
4
5BEGIN ISOLATION LEVEL REPEATABLE READ;
6-- Snapshot at transaction start; consistent reads
7
8BEGIN ISOLATION LEVEL SERIALIZABLE;
9-- Full isolation; detects conflicts and aborts
10-- Use for financial operations or when consistency is critical
11
12-- PostgreSQL: detect serialization failures
13BEGIN ISOLATION LEVEL SERIALIZABLE;
14UPDATE accounts SET balance = balance - 100 WHERE id = 1;
15UPDATE accounts SET balance = balance + 100 WHERE id = 2;
16COMMIT;
17-- If concurrent transaction modified same rows:
18-- ERROR: could not serialize access due to concurrent update
19-- Application must retry the transaction

best practice

Use READ COMMITTED for most workloads. Only escalate to SERIALIZABLE for critical sections where consistency is more important than throughput.
Deadlocks
deadlocks.sql
SQL
1-- Deadlock scenario:
2-- Transaction A: locks row 1, then tries to lock row 2
3-- Transaction B: locks row 2, then tries to lock row 1
4-- Both wait forever → deadlock detected, one is aborted
5
6-- Prevention: always lock rows in the same order
7-- Transaction A: UPDATE accounts WHERE id = 1 (then 2)
8-- Transaction B: UPDATE accounts WHERE id = 1 (then 2)
9
10-- PostgreSQL deadlock detection
11-- (deadlock_timeout = 1s by default)
12
13-- View deadlocks in logs
14SHOW log_lock_waits; -- off by default
15SET log_lock_waits = on;
16SET deadlock_timeout = '500ms';
17
18-- Monitor locks
19SELECT
20 blocked.pid AS blocked_pid,
21 blocked.query AS blocked_query,
22 blocking.pid AS blocking_pid,
23 blocking.query AS blocking_query
24FROM pg_stat_activity blocked
25JOIN pg_locks bl ON bl.pid = blocked.pid
26JOIN pg_locks kl ON kl.locktype = bl.locktype
27 AND kl.relation = bl.relation AND kl.pid != bl.pid
28JOIN pg_stat_activity blocking ON blocking.pid = kl.pid
29WHERE NOT bl.granted;
Savepoints
savepoints.sql
SQL
1-- Savepoints: partial rollback within a transaction
2BEGIN;
3
4INSERT INTO orders (user_id, total) VALUES (1, 99.99);
5
6SAVEPOINT order_created;
7
8INSERT INTO order_items (order_id, product_id, qty) VALUES (1, 42, 2);
9-- This might fail (foreign key violation)
10-- We can rollback to savepoint without losing the order
11
12ROLLBACK TO SAVEPOINT order_created;
13
14-- The order is still there, but the failed item was undone
15INSERT INTO order_items (order_id, product_id, qty) VALUES (1, 55, 1);
16COMMIT;
$Blueprint — Engineering Documentation·Section ID: DB-TX-01·Revision: 1.0