Databases 7 min read

How MySQL Prevents Phantom Reads: MVCC and Next‑Key Locks Explained

This article explains why phantom reads occur under MySQL's REPEATABLE READ isolation, how InnoDB uses MVCC for snapshot reads and next‑key locks for current reads, and demonstrates the mechanisms with code examples and version‑tracking diagrams.

Programmer DD
Programmer DD
Programmer DD
How MySQL Prevents Phantom Reads: MVCC and Next‑Key Locks Explained

1. Conclusion

Under the REPEATABLE READ isolation level, InnoDB solves phantom reads by combining MVCC (which handles snapshot reads) with next‑key locks (which handle current reads).

2. What Is a Phantom Read?

Consider two transactions: update table set name="hh" where id>3; Transaction A executes the update. Then Transaction B inserts a new row and commits:

insert into table values(11, "uu");
commit;

When Transaction A subsequently runs: select * from table where id>3 the result includes the newly inserted row (id 11, uu), demonstrating a phantom read. The effect is caused by the committed changes of Transaction B becoming visible to Transaction A.

Phantom reads differ from non‑repeatable reads: the former affect a range of rows, the latter affect a single row.

3. How Is It Solved?

3.1 Current Read (Locking Read)

Current reads (SELECT … FOR UPDATE/S, UPDATE, DELETE) acquire next‑key locks that lock the target row and the surrounding index interval. In the example, the statement select * from table where id>3 locks the row with id=3 and the range id>3, preventing other transactions from inserting rows into that range and thus avoiding phantom rows.

3.2 Ordinary Read (Snapshot Read)

Ordinary reads do not acquire locks; they rely on MVCC. Each row stores a creation version and a deletion version . Every transaction receives a monotonically increasing version number at start.

During REPEATABLE READ, the visibility rules are:

Read rows whose creation version ≤ current transaction version.

Read rows whose deletion version is NULL or > current transaction version.

These rules are applied to each DML operation:

SELECT

Read rows satisfying the two version conditions.

INSERT

Set the row’s creation version to the current transaction version.

UPDATE

Insert a new version of the row with the current transaction version as its creation version, and set the old row’s deletion version to the current transaction version.

DELETE

Set the row’s deletion version to the current transaction version.

Diagrams illustrating version handling:

Insert version diagram
Insert version diagram
Update version diagram
Update version diagram
Delete version diagram
Delete version diagram

Key point: a read must satisfy both conditions—creation version ≤ current transaction version and (deletion version is NULL or > current transaction version). This ensures that rows inserted by later transactions (like Transaction B) are invisible to the earlier transaction, eliminating phantom reads.

4. Additional Note

In READ COMMITTED mode, MVCC cannot prevent phantom reads or non‑repeatable reads because each read sees the latest committed snapshot, which may change after each statement.

Other References

https://segmentfault.com/a/1190000012669504
Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

databasemysqlMVCCIsolation LevelNext-key Lockphantom read
Programmer DD
Written by

Programmer DD

A tinkering programmer and author of "Spring Cloud Microservices in Action"

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.