In the previous post, we understood isolation levels through the lens of their anomalies i.e., what goes wrong when transactions interleave too freely.
But knowing what to prevent is only half the story. Databases must also decide how to prevent it.
That’s where concurrency control mechanisms come in. They are the machinery behind isolation, the algorithms that shape which anomalies can happen, and which never will.
1. Two-Phase Locking (2PL): Serializability Through Restraint
Two-Phase Locking (2PL) is the oldest and most intuitive concurrency control method. It enforces serializability by strictly ordering access through locks.
Each transaction operates in two phases:
| Phase | Action |
|---|---|
| Growing Phase | Acquires locks before reading or writing data. |
| Shrinking Phase | Releases all locks only after commit or abort. |
This simple rule i.e., never release a lock before you’re done acquiring them, guarantees that no other transaction can slip in between operations.
| Anomalies Prevented | Still Possible |
|---|---|
| Dirty Read, Non-repeatable Read, Phantom Read, Write Skew | None |
But the price of purity is concurrency. Once a transaction holds a lock, others must wait, a safe but often slow guarantee.
2. Optimistic Concurrency Control (OCC): Serializability by Validation
Where 2PL relies on blocking, OCC bets on optimism. It assumes conflicts are rare, so it lets transactions run freely, checking for problems only at commit time.
| Phase | Action |
|---|---|
| Read Phase | Transaction reads data and performs computations without locks. |
| Validation Phase | Before commit, it checks if any other transaction modified the same data it read. |
| Write Phase | If validation succeeds, changes are committed; otherwise, the transaction is rolled back. |
| Anomalies Prevented | Still Possible |
|---|---|
| Dirty Read, Non-repeatable Read, Phantom Read, Write Skew | None (if validation is strict) |
OCC achieves serializability by rejecting overlapping conflicting transactions rather than blocking them. The cost is higher abort rates under contention therefore it is ideal for read-heavy workloads, but less so for write-heavy systems.
3. Multi-Version Concurrency Control (MVCC): Snapshots for Everyone
MVCC trades locks for versions. Instead of blocking readers, the database keeps multiple versions of each record, each tagged with a transaction timestamp.
Every transaction reads from a snapshot, a consistent view of the database as it existed when it began.
| Step | MVCC Behaviour |
|---|---|
| Read | Returns the latest committed version as of the transaction’s start time. |
| Write | Creates a new version with the transaction’s commit timestamp. |
| Commit | Checks if any other concurrent writer modified the same rows (write–write conflict). |
| Anomalies Prevented | Still Possible |
|---|---|
| Dirty Read, Non-repeatable Read, Phantom Read | Write Skew |
MVCC enables high concurrency. Readers never block writers, and writers rarely block readers. However, its reliance on snapshots introduces the write skew anomaly, where two consistent snapshots lead to an inconsistent outcome.
4. Serializable Snapshot Isolation (SSI): Serializability Without Locks
SSI builds on MVCC but adds dependency tracking to close the serializability gap. It monitors how transactions depend on each other through their reads and writes. When T1 reads data that T2 later writes, a dependency edge is formed (T1 -> T2). If such dependencies ever form a cycle, the system aborts one transaction to break it, ensuring a conflict-free, acyclic order.
| Anomalies Prevented | Still Possible |
|---|---|
| Dirty Read, Non-repeatable Read, Phantom Read, Write Skew | None |
SSI achieves true serializability without locking reads, retaining MVCC’s performance benefits while restoring its correctness.
Comparing Concurrency Control Mechanisms
Different concurrency control algorithms make different trade-offs between correctness, concurrency, and complexity. Each mechanism prevents a certain set of anomalies, decides transaction order differently, and suits different workloads.
| Mechanism | How It Decides Order | Anomalies Prevented | Concurrency | Best Suited For |
|---|---|---|---|---|
| Two-Phase Locking (2PL) | Lock acquisition order | All | Low | Maximum correctness and strong consistency |
| Optimistic Concurrency Control (OCC) | Validation at commit | All | Medium | Distributed or high-latency systems |
| Multi-Version Concurrency Control (MVCC) | Snapshot timestamp ordering | Dirty, Non-repeatable, Phantom | High | Read-heavy workloads needing high throughput |
| Serializable Snapshot Isolation (SSI) | Dependency tracking | All | High | Predictable behaviour without blocking |
Conclusion
Isolation levels describe what a database guarantees. Concurrency control mechanisms decide how it keeps that promise.
Locking ensures order by force; OCC enforces it by validation; MVCC maintains it through time travel; SSI safeguards it through dependency tracking. Different paths, same goal i.e., to make concurrency feel like serial execution.