Databases for Developers

Lesson 5 of 10 · 20 min

x
50%

Transactions & ACID

A transaction is a group of operations that either all succeed or all fail together. ACID is the set of guarantees that make this work: Atomicity (all-or-nothing), Consistency (data stays valid), Isolation (concurrent transactions don't interfere), and Durability (committed data survives crashes). Isolation levels control how visible uncommitted changes are to other transactions. Read Committed (the Postgres default) prevents dirty reads but allows non-repeatable reads. Serializable provides the strongest guarantee but reduces concurrency. Most applications work well at Read Committed — only use Serializable for financial operations where phantom reads would cause real money problems.

Before
Unsafe — partial failure leaves dirty state
// If second update fails, money disappears
await db.query(
  'UPDATE accounts SET balance = balance - 100 WHERE id = 1'
);
await db.query(
  'UPDATE accounts SET balance = balance + 100 WHERE id = 2'
);
After
Safe — both updates succeed or both roll back
await db.query('BEGIN');
try {
  await db.query(
    'UPDATE accounts SET balance = balance - 100 WHERE id = 1'
  );
  await db.query(
    'UPDATE accounts SET balance = balance + 100 WHERE id = 2'
  );
  await db.query('COMMIT');
} catch (err) {
  await db.query('ROLLBACK');
  throw err;
}

Key Takeaway

Always wrap multi-step mutations in a transaction — partial success is worse than total failure.

PreviousNext Lesson