MySQL · lesson 4 of 8
Intermediate
6- 2 Composite Indexes: The Filesort a Single-Column Index Can't Avoid
- 3 A Missing Join Condition Turns 4,000 Rows Into 8 Million
- 4 Isolation Levels: The Same Transaction Reading Two Different Values
- 5 A Real Deadlock: Error 1213, and the Lock-Order Fix
- 6 Stored Procedures and Triggers: Code That Runs Without Being Asked
- 8 Backup and Recovery: What a Restore Actually Gives Back
Also part of MySQL
1Also part of: Databases
Isolation Levels: The Same Transaction Reading Two Different Values
Under MySQL's default REPEATABLE READ, a transaction reads the same value twice even after another session commits a change in between. Switch to READ COMMITTED and the second read sees the new value — a real, measured non-repeatable read.
By SkillByExample · Published
The same query, run twice inside the same transaction — one isolation level guarantees they match, the other doesn’t.
REPEATABLE READ (the default): two reads, same answer
-- Session A
START TRANSACTION;
SELECT balance AS first_read FROM accounts WHERE id = 2;
first_read
300.00
-- Session B, while session A's transaction is still open
UPDATE accounts SET balance = 999.00 WHERE id = 2;
-- back in session A, same still-open transaction
SELECT balance AS second_read_same_txn FROM accounts WHERE id = 2;
COMMIT;
second_read_same_txn
300.00
Session B’s update genuinely committed — a fresh connection querying accounts right now
would see 999.00. But session A’s transaction reads 300.00 both times, because
REPEATABLE READ (MySQL’s default) serves every plain read in a transaction from the same
consistent snapshot, taken when the transaction’s first read happened.
READ COMMITTED: the same setup, a different answer the second time
-- Session A
SET SESSION transaction_isolation = 'READ-COMMITTED';
START TRANSACTION;
SELECT balance AS first_read FROM accounts WHERE id = 2;
first_read
300.00
-- Session B commits the same change while A's transaction is open
UPDATE accounts SET balance = 999.00 WHERE id = 2;
-- back in session A, same transaction
SELECT balance AS second_read_same_txn FROM accounts WHERE id = 2;
COMMIT;
second_read_same_txn
999.00
Same transaction, same query, run twice — and this time the second read sees 999.00, the
value session B committed in between. READ COMMITTED takes a fresh snapshot for every
individual statement rather than one snapshot for the whole transaction, so a commit that
happens between two reads becomes visible to the second one. This is a real non-repeatable
read: the same row, read twice in one transaction, disagreeing with itself.
Practice
1. Check your current session's isolation level directly.
SELECT @@transaction_isolation;
@@transaction_isolation
REPEATABLE-READ
REPEATABLE-READ is MySQL’s compiled-in default — every new connection starts here unless a
session or the server config sets something else.
2. Confirm a fresh connection (not inside either transaction) always sees the current committed value, regardless of isolation level.
-- a brand-new connection, no open transaction
SELECT balance FROM accounts WHERE id = 2;
balance
999.00
Isolation levels only change what an already-open transaction sees across multiple reads
— a fresh, standalone query with no transaction of its own always reads the latest committed
value, under either isolation level. The snapshot behavior only kicks in once START TRANSACTION has begun one.
3. Reset the session back to the default and confirm the guarantee returns.
SET SESSION transaction_isolation = 'REPEATABLE-READ';
START TRANSACTION;
SELECT balance AS first_read FROM accounts WHERE id = 2;
-- (another session updates and commits to 1500.00 here)
SELECT balance AS second_read FROM accounts WHERE id = 2;
COMMIT;
first_read
999.00
second_read
999.00
Back to matching reads, even though a concurrent session committed 1500.00 in between (a
fresh connection now sees that value) — SET SESSION changes are session-scoped and don’t
persist as a new server default, so explicitly resetting it is the reliable way to return to
REPEATABLE READ behavior within the same long-lived connection.
Next: locking and deadlocks — a real blocked write, and a real deadlock with the exact error MySQL raises.