Isolation Levels Explained Through Conflicts

This blog post is another take at isolation levels, a topic I first explored in one of my earlier posts. The motivation this time is to relook at isolation levels from a different perspective so that isolation levels feel understood rather than merely studied.

In a previous post, we saw how databases detect and handle Read-Write (RW) and Write-Write (WW) conflicts to preserve serializability. But not every system chooses to hold the rope that tight. Some loosen their grip, allowing more concurrency at the cost of occasional anomalies. In fact, isolation levels are nothing but different ways of loosening that noose, deciding how much concurrency we allow before anomalies start to slip in.

Let’s unwind this perspective, strand by strand, to see how isolation levels really emerge from the push and pull of conflicts.

RW and WW Are the Primitive Edges While Anomalies Are the Patterns They Form

Every anomaly in the isolation spectrum is nothing but a different pattern built from RW and WW edges.

RW conflicts govern what a transaction sees. WW conflicts govern whose change finally lands. Relax either, and you invite a family of anomalies. However, every isolation anomaly (lost update, write skew, etc.) is not just caused by a single RW or WW conflict, but by how these edges connect in a transaction dependency graph.

Conflict Type What It Influences Typical Anomalies
RW What a transaction believes about the world Dirty Read, Non-repeatable Read, Phantom Read, Write Skew
WW Whose belief becomes truth Dirty Write, Lost Update
RW + WW cycles Interlocking reads and writes Write Skew, Lost Update

If you imagine each transaction as a node, these edges form a directed graph. When that graph contains a cycle, you get a serializability violation, another anomaly.

The point I am trying to make here is that the correlation is not 1-to-1, but foundational. RW and WW are the building blocks; anomalies are the structures built from them.

Let's explore this idea a bit more in detail:

1. RW Conflicts -> Read-side Anomalies (mostly)

RW conflicts are at the heart of read-related anomalies, because they involve one transaction reading something that another later writes.

RW-Driven Anomaly How the RW Conflict Manifests
Dirty Read T1 reads uncommitted data that T2 wrote -> RW conflict with uncommitted writer
Non-repeatable Read T1 reads a row; T2 writes a new value; T1 re-reads -> RW conflict changes what T1 sees
Phantom Read T1 runs a range query; T2 inserts a new matching row -> predicate-level RW conflict
Write Skew Both transactions read each other’s state before writing -> two RW edges forming a cycle

So yes, read anomalies are largely symptoms of unrestrained RW dependencies, and tightening RW control (via locks, validation, or snapshots) progressively eliminates them.

2. WW Conflicts -> Write-side Anomalies (mostly)

WW conflicts arise when two writers contend for the same item. They are directly tied to write-anomalies like overwrites and lost updates.

WW-Driven Anomaly How the WW Conflict Manifests
Dirty Write T1 and T2 both update the same row before either commits -> overlapping uncommitted writes
Lost Update T1 writes after reading stale data; T2’s later write overwrites T1’s result
Write Skew Indirectly involves WW logic, two writers modify different rows whose combination violates an invariant

WW conflicts are often easier to detect. Databases can simply serialize writes to the same record. That’s why dirty writes are universally forbidden, and lost updates vanish once WW conflicts are properly managed.

3. Some Anomalies Require Both RW and WW Edges

Not all anomalies are purely read-side or write-side. Some emerge only when both RW and WW edges participate in the same dependency cycle i.e., when a transaction reads something another later writes (RW), and then overwrites or depends on that same data in return (WW or RW back).

These hybrid cycles are what make anomalies like Lost Update and Write Skew deceptively subtle.

Lost Update: RW<->RW Cycle, Exposed by WW Overwrite
Two transactions read the same old value before either writes, and then both attempt to update the same record.

Step Description Conflict Type
1 Both transactions read the same old data (e.g., balance = 100) RW - each reads data the other later modifies
2 Both decide to update that value RW<->RW - mutual stale reads form a logical cycle
3 One write overwrites the other’s result WW - the lost update becomes visible

The cycle arises from two RW dependencies, each transaction made decisions on values the other later changed. The WW overwrite doesn’t cause the cycle, it merely exposes the consequence: one update silently disappears.

Write Skew: Mutual RW<->RW Cycle
Two transactions read disjoint rows and then update them in a way that violates a shared invariant.

Step Description Conflict Type
1 T1 reads a value that T2 will later modify RW
2 T2 reads a value that T1 will later modify RW
3 Both write their own rows based on outdated reads RW<->RW cycle

In real time, each transaction reads a current committed state. But in logical order, each depends on data that the other later changes, so the dependency graph forms a cycle, both relying on each other’s future writes.

Watching the Noose Tighten

So far, we’ve dissected conflicts in isolation, understanding how RW and WW edges shape every anomaly. But isolation levels aren’t just abstract rules about which edges are allowed or blocked. They are progressive states of restraint, each tightening its grip on these conflicts a little more.

Now that we know what needs to be contained, let’s see how different isolation levels actually do it, how each one pulls the rope tighter around RW and WW interactions until serializability finally holds.

1. Read Uncommitted: the Noose Is Off

The system neither blocks nor validates anything.

Scenario What Happens Anomaly
T2 updates a row; T1 reads it before commit T1 sees uncommitted data Dirty Read (Allowed)
T1 re-reads after T2 commits Values change mid-transaction Non-repeatable Read (Allowed)
T1 reruns a range query after T2 inserts Predicate returns new rows Phantom Read (Allowed)
T1 and T2 write same record uncommitted State depends on rollbacks Dirty Write (Prevented)
T1 writes after stale read, T2 writes later Earlier update lost Lost Update (Allowed)
Two transactions read then write different rows Invariant breaks Write Skew (Allowed)

Everything that can go wrong does. The rope lies slack on the floor.

2. Read Committed: The First Tightening

Only committed data may be read or overwritten.

Scenario What Happens Anomaly
Reads uncommitted data Blocked / old value returned Dirty Read (Prevented)
Re-reads same row after another commit Sees new value Non-repeatable Read (Allowed)
Re-runs predicate after insert Sees new rows Phantom Read (Allowed)
Concurrent writes to same row Last writer wins Lost Update (Allowed)
Overwrites uncommitted data Forbidden Dirty Write (Prevented)
Separate rows read-before-write Invariant can break Write Skew (Allowed)

Dirty operations are gone, but RW conflicts still slip between statements. The noose tightens — just a little.

3. Repeatable Read / Snapshot Isolation: Steady Sight

Each transaction sees a consistent snapshot from start to finish.

Scenario What Happens Anomaly
Reads uncommitted data Hidden by snapshot Dirty Read (Prevented)
Re-reads row later Always same value Non-repeatable Read (Prevented)
Range query after insert New rows may appear Phantom Read (Allowed)
Same row updated by two writers Validation aborts one Lost Update (Prevented)
Overwrite of uncommitted write Forbidden Dirty Write (Prevented)
Two writers read each other’s rows first Both commit inconsistent state Write Skew (Allowed)

RW edges are now tamed by snapshots; WW edges handled at commit.
Only predicate-level phantoms and cross-row write skews remain.

4. Serializable: The Final Knot

All RW and WW edges are tracked; any cycle causes an abort.

Scenario What Happens Anomaly
Reads uncommitted data Never happens Dirty Read (Prevented)
Re-reads row after commit Stable snapshot or abort Non-repeatable Read (Prevented)
Range query after insert Cycle detected -> abort Phantom Read (Prevented)
Concurrent writes Ordered or aborted Lost Update (Prevented)
Overwrites uncommitted data Forbidden Dirty Write (Prevented)
Cross-row invariant check Cycle detected -> abort Write Skew (Prevented)

The rope is taut, every motion serialised. No anomalies survive.

Summary: Isolation Levels and Anomalies Prevented

Isolation Level Dirty Read Non-repeatable Read Phantom Read Lost Update Dirty Write Write Skew
Read Uncommitted Allowed Allowed Allowed Allowed Prevented Allowed
Read Committed Prevented Allowed Allowed Allowed Prevented Allowed
Repeatable Read / Snapshot Isolation Prevented Prevented Allowed Prevented Prevented Allowed
Serializable Prevented Prevented Prevented Prevented Prevented Prevented

Even Read Uncommitted databases forbid dirty writes to preserve recovery correctness.

Conclusion

In this blog, we saw how all isolation levels are variations on a single theme, managing RW and WW conflicts. Relax both, and anomalies multiply. Restrain them carefully, and transactions appear serial.

Each level on the isolation spectrum represents a different policy for how much concurrency to risk before safety is enforced. At one end, performance thrives on trust; at the other, correctness reigns through control.

Understanding these edges and the patterns they form turns isolation levels from a checklist of anomalies into a system of cause and effect.
It’s not about memorising which anomaly happens where, but recognising how loosening or tightening the grip on conflicts shapes everything that follows.

To sum it all up. RW conflicts drive read-anomalies. WW conflicts drive write-anomalies. Their interaction drives the truly subtle anomalies (write skew, lost update). The tighter you grip around these two conflict types, the closer you move toward serializability.

Conflict Type Primary Anomaly Family Typical Prevention Isolation Levels That Block It
RW Dirty Read, Non-repeatable Read, Phantom Read, Write Skew Lock readers or use consistent snapshots Read Committed -> Serializable
WW Dirty Write, Lost Update Lock writers or abort overlapping writes All levels ≥ Read Committed
RW + WW (cyclic) Write Skew, Lost Update (composite) Detect cycles / serial-order validation Serializable
Show Comments