What Phantom Read shows you
Every relational database gives you a dial called the isolation level.
Turn it down and concurrent transactions run faster but can corrupt each
other's view of the data; turn it up and the database protects you at the
cost of aborting more commits. Most tutorials teach this as a grid of
"prevents X, allows Y" with no way to see the machinery underneath.
Phantom Read runs that machinery in the browser: a small multi-version
concurrency control (MVCC) engine that keeps a version chain per row,
takes a snapshot when each transaction begins, and resolves every read
with the same visibility rules Postgres uses.
Pick a scenario, set an isolation level for each of the two transactions,
and step forward one action at a time. You watch the shared table, the
version chain, and each transaction's snapshot change on every step, so
the anomaly is something you observe rather than something a diagram
asserts. Raise the level and replay the same script to see the anomaly
disappear, or the database abort the losing commit to keep your data
consistent.
Frequently asked questions
- What is a database isolation level?
-
It is the guarantee a database makes about how much one transaction can
see of another that is running at the same time. The SQL standard names
four: Read Uncommitted, Read Committed, Repeatable Read, and
Serializable. Phantom Read models the top three, the ones a real MVCC
database like Postgres actually offers.
- What is a phantom read?
-
It happens when a transaction runs the same range query twice and the
second run returns a row that was not there before, because another
transaction inserted and committed it in between. Repeatable Read stops
it by freezing the reading transaction's snapshot at the moment it
began, so the new row stays invisible.
- Does Repeatable Read prevent write skew?
-
No, and that surprise is the reason this tool exists. Two transactions
can each read a value, check an invariant, and write a different row.
Both snapshots were valid on their own, both commit, and together they
break the invariant. Only Serializable catches it, by detecting the
read-write conflict at commit time and aborting one transaction.
- Is this a real database?
-
No. It is a faithful simulation of the visibility and conflict-detection
rules a real MVCC engine uses, written in plain JavaScript so it runs
with no server and no install. The same engine code powers both the UI
and the test suite, so what you see on screen is exactly what the tests
assert.
- Which isolation level should I use in production?
-
It depends on your workload, but the honest default is: use the highest
level your database offers by default (often Read Committed), and reach
for Serializable on the specific transactions that guard an invariant
across more than one row. Phantom Read helps you feel where that line
is by letting you break the invariant and then protect it.