Transactions, ACID & Concurrency

A transaction is a sequence of database operations treated as a single unit: either everything succeeds, or nothing does. Transactions are how databases protect your data from crashes, bugs, and concurrent users stepping on each other.

What is a Transaction?#

sql
Loading editor…

If the server crashes between the two UPDATE statements, the partially-applied transfer would leave Alice's account debited but Bob's not credited — money destroyed. The transaction prevents this: either both updates apply, or neither does.

ACID Properties#

Atomicity#

The transaction is all-or-nothing. If any statement fails (or the server crashes), the entire transaction is rolled back as if it never happened.

sql
Loading editor…

Consistency#

A transaction takes the database from one valid state to another valid state. All constraints — NOT NULL, UNIQUE, foreign keys, CHECK constraints — must hold after every commit.

sql
Loading editor…

Isolation#

Concurrent transactions behave as if they run serially — they don't see each other's uncommitted changes.

sql
Loading editor…

Durability#

Once a transaction commits, the changes survive crashes. The DB writes a Write-Ahead Log (WAL) to disk before applying changes. On restart, uncommitted WAL entries are discarded; committed ones are replayed.

text
Loading editor…

Concurrency Problems#

Without careful isolation, concurrent transactions cause anomalies:

Dirty Read#

Reading uncommitted changes from another transaction. If that transaction rolls back, you read data that never existed.

Non-Repeatable Read#

Reading the same row twice within a transaction and getting different values because another transaction committed a change in between.

Phantom Read#

Running the same query twice and getting different sets of rows because another transaction inserted or deleted rows in between.

text
Loading editor…

Isolation Levels#

SQL defines four isolation levels, trading consistency for concurrency:

LevelDirty ReadNon-Repeatable ReadPhantom ReadHow
Read UncommittedPossiblePossiblePossibleNo locks
Read CommittedNoPossiblePossibleLock on write, release on read
Repeatable ReadNoNoPossible (MySQL: No)Hold read locks until commit
SerializableNoNoNoFull serial-equivalent execution
sql
Loading editor…

Most production databases default to Read Committed (PostgreSQL, SQL Server) or Repeatable Read (MySQL InnoDB).

MVCC — Multi-Version Concurrency Control#

Modern databases (PostgreSQL, MySQL InnoDB, Oracle) implement isolation using MVCC rather than locking everything:

  • Each row maintains multiple versions with timestamps
  • Writers create new versions; old versions remain for existing readers
  • Readers see a snapshot of the database as of their transaction start time
  • No read-write conflicts — readers never block writers
text
Loading editor…

Savepoints#

You can create named checkpoints within a transaction and roll back to them partially:

sql
Loading editor…

Deadlocks in the Database#

Two transactions can deadlock if each holds a lock the other needs:

sql
Loading editor…

The database detects this and kills one transaction (the "victim"). The victim's transaction is rolled back automatically — the application should retry.

Prevention: always lock rows in the same order across all transactions.

Python: transactions with psycopg2#

python
Loading editor…

Key Takeaways#

  • Transactions are all-or-nothing: COMMIT applies everything, ROLLBACK undoes everything
  • ACID guarantees data integrity across failures and concurrent users
  • Isolation levels trade performance for correctness: higher isolation = fewer anomalies = more locking
  • MVCC lets readers and writers proceed concurrently without blocking each other
  • Database deadlocks are detected automatically; design transactions to avoid them by locking in consistent order