# Transaction isolation levels

> Transaction isolation levels define which effects of concurrent transactions a transaction can observe and which interference the database prevents. In system design interviews, they help explain why wrapping a balance check, seat reservation, or inventory update in a transaction may still leave a race.

Source: https://sysround.com/concepts/isolation-levels
Updated: 2026-11-05


## How transaction isolation levels works

Start with the invariant, not the isolation-level name. If an account has $100 and two requests each spend $80, both might read $100 before either writes. Atomic transactions prevent partial commits, but the isolation level and update pattern determine whether both requests can succeed.

Read uncommitted can permit dirty reads: reading changes that another transaction has not committed and might roll back. Read committed prevents dirty reads, but repeated queries can observe different committed data. For example, a second balance query may see a payment committed after the first query.

Repeatable read prevents non-repeatable reads of previously read rows. Under the SQL standard, it can still allow phantoms: a repeated range query returns newly matching rows. Actual implementations differ; PostgreSQL repeatable read uses snapshot isolation, while MySQL InnoDB combines snapshot reads with locking behavior that depends on the statement.

Snapshot isolation typically gives ordinary reads a stable snapshot established near the start of the transaction, plus visibility of the transaction's own writes. Conflicting concurrent writes to the same row cannot both commit under snapshot isolation, but writes to different rows can produce write skew: each transaction passes a check against its snapshot while their combined writes violate a rule.

Serializable guarantees that committed transactions have an outcome equivalent to some serial execution. The database may enforce this with locking, dependency tracking and aborts, or other mechanisms. It prevents write skew, but applications must handle transaction failures and retries; it does not mean transactions literally run one at a time.

Choose an isolation level together with a concurrency-control pattern. A conditional update such as UPDATE accounts SET balance = balance - 80 WHERE id = 7 AND balance >= 80 can protect a single-row balance at read committed when the database evaluates the condition against the current row under write concurrency control; check that one row changed. Multi-row rules may need ordered row locks, constraints, a shared guard row, or serializable execution.

## Worked example: Snapshot isolation can overspend a shared account

An account has two funding buckets, each holding $100. The rule allows a bucket to go negative as long as the account's combined balance stays nonnegative. Two concurrent $150 withdrawals each read a total of $200 under snapshot isolation. Transaction A debits bucket A to -$50; transaction B debits bucket B to -$50. They update different rows, so both can commit, leaving a total of -$100. This is write skew, not a dirty read. Use serializable execution with whole-transaction retries, or require every withdrawal to lock the same account guard row before checking and updating the buckets. Locking only the bucket being debited does not protect the shared invariant.

## Trade-offs

- **Read committed needs deliberate write patterns.** It can support correct transactions with atomic conditional updates and constraints, but an unprotected read-check-write sequence remains unsafe.
- **Stable snapshots are not serializable.** Snapshot isolation makes repeated reads consistent while still allowing write skew across different rows.
- **Stronger isolation shifts the cost.** Depending on the implementation, stronger guarantees can mean more lock waiting, deadlocks, validation work, or transaction aborts.
- **Long transactions consume resources.** Long-lived snapshots retain old row versions, while long-held locks can delay other transactions.
- **Retries belong in the application design.** Retry aborted transactions from the beginning with bounded backoff, and keep irreversible external side effects outside the retried transaction.
- **Guarantees have a boundary.** A database transaction does not automatically isolate cache reads, asynchronous replicas, external payments, or writes in another database.

## When to use it in a system design interview

- Concurrent requests compete for scarce resources such as seats, room inventory, cash, or account-wide session slots.
- A transaction checks a condition and then changes data, especially when the condition spans multiple rows.
- Several queries must produce one consistent view, such as a financial report or a database export.
- The interviewer asks whether a transaction alone prevents double booking, overspending, lost updates, or duplicate allocation.

## How to bring it up in the interview

- State the invariant explicitly, then walk through two concurrent transactions that could break it.
- Name the database and relevant statement semantics before claiming what repeatable read or snapshot isolation guarantees; interviewers often probe implementation differences.
- Choose the narrowest sufficient mechanism: a unique constraint, conditional update, explicit lock, or serializable transaction, and explain why it protects the invariant.
- Explain what happens under contention: lock ordering, deadlocks, serialization failures, retry limits, and what response the client receives.
- Define the transaction boundary and keep network calls out of it; expect follow-up questions about payment retries, idempotency, and cross-service coordination.

## Common mistakes

- Assuming atomicity means concurrent transactions cannot violate business rules.
- Treating repeatable read, snapshot isolation, and serializable as interchangeable.
- Assuming a stable snapshot prevents write skew across different rows.
- Locking only existing query results when the invariant also depends on absent rows or future inserts.
- Retrying only the failed statement instead of restarting the transaction, or repeating an external charge during a transaction retry.

## Interview questions where it comes up

- [Design a ticket booking system like Ticketmaster](https://sysround.com/questions/design-ticketmaster): Preventing concurrent seat holds requires explaining why a transaction needs conditional writes, constraints, or appropriate locking and isolation.
- [Design a hotel booking system](https://sysround.com/questions/design-hotel-booking-system): A multi-night reservation must check and reserve every night's inventory without allowing concurrent transactions to oversell capacity.
- [Design a stock trading app like Robinhood](https://sysround.com/questions/design-robinhood): Concurrent orders must reserve cash and shares without both spending the same available balance.
- [Design a payment system](https://sysround.com/questions/design-payment-system): Concurrent refunds and payouts require transactional checks that preserve refundable amounts and spendable merchant balances.
- [Design a wire transfer system](https://sysround.com/questions/design-wire-transfer-system): Atomic ledger entries must be combined with concurrency control so simultaneous transfers cannot violate account balance rules.
- [Design Netflix's concurrent screen limit](https://sysround.com/questions/design-netflix-screen-limit): Concurrent session starts can both pass a count-then-insert check unless slot allocation protects the account-wide limit.

## FAQ

### What is the difference between read committed and repeatable read?

Read committed prevents dirty reads but allows a later query to see changes committed since an earlier query. Repeatable read keeps previously read rows stable within the transaction. Phantom behavior, locking reads, and write-conflict handling depend on the database implementation.

### Is snapshot isolation the same as serializable isolation?

No. Snapshot isolation gives a consistent snapshot and prevents concurrent conflicting writes to the same row from both committing, but it can allow write skew across different rows. Serializable also prevents those nonserializable outcomes, potentially by aborting a transaction that the application must retry.

### Which isolation level prevents double booking?

There is no universal isolation-level answer because the schema and reservation operation matter. A unique constraint or an atomic conditional update can protect a single seat at read committed. Reservations based on range queries or multi-row capacity checks may require additional locking, suitable constraints, or serializable transactions.

## Related concepts

- [MVCC](https://sysround.com/concepts/mvcc)
- [Serializability](https://sysround.com/concepts/serializability)
- [Two-phase locking](https://sysround.com/concepts/two-phase-locking)
- [Optimistic locking](https://sysround.com/concepts/optimistic-locking)


---
SysRound (https://sysround.com) is an AI practice tool for system design interviews: a voice or typed AI interviewer, a shared whiteboard, then feedback on every skill and a model answer. Its feedback is AI-generated and can be wrong.
