Skip to content

Non-repeatable read ​

A non-repeatable read is reading the same row twice inside one transaction and getting different data, because another transaction committed a change in between. Nothing you read was uncommitted (every value was real), yet your transaction can no longer trust its own earlier reads.

Session A
Session B
BEGIN
SELECT balance→ 100
UPDATE accounts SET balance = 200
COMMIT
SELECT balance→ 200 ← same query, different answer
COMMIT

The timeline is illustrative; linked Scenarios provide the actual setup and assertions.

Formally P2. At READ COMMITTED, plain consistent SELECTs use new statement snapshots, plus own prior writes. Updating and locking commands have separate rules; a complex updating command is not promised one globally consistent view. See operation scope.

Read skew ​

Non-repeatable reads have a nastier multi-row cousin, read skew (formally Adya's G-single): read row 1, let someone move money to row 2, read row 2. Every row you saw was committed and correct, yet the combination existed at no point in time:

Session A
Session B
SELECT balance WHERE id = 1→ 500
moves 200 from account 1 to account 2
COMMIT
SELECT balance WHERE id = 2→ 500 ← total reads 1000; it was never 1000

An application that combines these reads as one simultaneous total can compute an incorrect result. No backup program or report publication runs here.

Who prevents it ​

LevelSQL standardPostgreSQLMySQL (InnoDB)
READ COMMITTEDpermittedhappens (proof)happens (proof)
REPEATABLE READpreventedprevented (proof)prevented for plain SELECTs (proof); UPDATE/DELETE are current reads that bypass the snapshot
SERIALIZABLEpreventedpreventedprevented

The stable-read contract excludes later concurrent commits in one REPEATABLE READ transaction. PostgreSQL establishes its snapshot at the first non-control statement; InnoDB at the first consistent read. Own writes remain visible in both. SERIALIZABLE exclusions in the table are documented/derived support, not extra executions; InnoDB's explicit-transaction and autocommit distinction matters. See the level contracts and marked catalog derivations.

  • Phantom read, the same effect on a set of rows: the rows you saw don't change, but new ones appear.
  • Lost update: what happens when you write back through a stale read instead of merely looking at it.

See it happen ​

MIT Licensed · Every transcript on this site was generated by a real database run against MySQL 8.4.11 and PostgreSQL 18.6 at 8fa27b8; shared YAML has an independent psycopg/PyMySQL check.