Isolation is the "I" in ACID. When thousands of concurrent users all read and write data simultaneously, how "sheltered" is your transaction from what others are doing? Isolation Levels let you configure this trade-off: more isolation = safer data, but more locks and slower performance.
Before understanding isolation levels, understand the problems they solve:
User A reads data that User B has modified but not yet committed. If User B rolls back, User A has read "fake" data that technically never existed.
B: UPDATE Balance = 0 (not committed yet)
A: SELECT Balance β sees 0 β DIRTY READ
B: ROLLBACK (Balance goes back to 1000)
A: Made a decision based on a balance of 0 that never existed!
User A reads the same row twice and gets different values because User B committed a change between the two reads.
A: SELECT Balance β 1000
B: UPDATE Balance = 500; COMMIT
A: SELECT Balance again β 500 β Different! Non-Repeatable Read
User A runs a query twice and gets a different number of rows because User B inserted or deleted rows between the two reads.
A: SELECT * FROM Orders WHERE Amount > 500 β 10 rows
B: INSERT INTO Orders (Amount=800); COMMIT
A: Same SELECT again β 11 rows β An extra "phantom" row appeared!
MySQL InnoDB supports all four standard SQL isolation levels:
| Level | Dirty Reads | Non-Repeatable Reads | Phantom Reads | Performance |
|---|---|---|---|---|
| READ UNCOMMITTED | β Possible | β Possible | β Possible | π Fastest |
| READ COMMITTED | β Prevented | β Possible | β Possible | β‘ Fast |
| REPEATABLE READ | β Prevented | β Prevented | β Prevented* | πΆ Moderate |
| SERIALIZABLE | β Prevented | β Prevented | β Prevented | π’ Slowest |
*MySQL's REPEATABLE READ also prevents Phantom Reads (unique to InnoDB's MVCC implementation β better than the SQL standard requires)
Default in MySQL: REPEATABLE READ β the best balance of safety and performance.
How does MySQL prevent Dirty Reads without locking every row being read? Multi-Version Concurrency Control (MVCC).
When a transaction starts:
- MySQL takes an invisible "Snapshot" of the database state at that exact moment.
- All reads within the transaction see data from that snapshot, regardless of what other sessions commit.
- Other sessions read their own snapshots simultaneously.
- Writes still use row-level locks β but reads never block writes, and writes never block reads.
This is why MySQL is fast: Reads and writes don't block each other. MVCC ensures consistency without the performance penalty of locking every read.
Reads data even from uncommitted transactions. Never use in production.
SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
-- Scenario: Bank balance shows βΉ0 because another session is mid-transfer (not committed).
-- You might deny a customer credit based on a temporary phantom βΉ0 balance.Only reads committed data. Prevents dirty reads. Widely used in OLTP systems.
SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;
-- Scenario: Each SELECT in your transaction shows the latest committed data.
-- Good for: Most business applications, reporting dashboards.Your transaction always sees the same data β frozen at the moment the transaction began. Prevents dirty reads AND non-repeatable reads.
-- Default β usually no need to set explicitly
SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ;
-- Scenario: A financial report transaction sees consistent totals even as new transactions are posted.Every transaction runs as if it's the only one in the system. Completely safe but very slow β places shared locks on everything read.
SET SESSION TRANSACTION ISOLATION LEVEL SERIALIZABLE;
-- Scenario: A government revenue calculation that absolutely cannot have any variation.
-- Tradeoff: Application throughput drops significantly under load.-- Check current isolation level
SELECT @@transaction_isolation; -- MySQL 8.0+
SELECT @@tx_isolation; -- MySQL 5.7 (old syntax)
-- Change for current session only
SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;
-- Change globally (all new connections)
SET GLOBAL TRANSACTION ISOLATION LEVEL REPEATABLE READ;
-- Change for next transaction only
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
START TRANSACTION;
-- ... this transaction runs under SERIALIZABLE ...
COMMIT;
-- Next transaction returns to session defaultExample 1 β Banking: Use REPEATABLE READ (Default)
-- Generating a bank statement for the month
-- Must see consistent balances throughout the entire report generation
START TRANSACTION; -- Takes a snapshot at this moment
SELECT SUM(Amount) FROM Transactions WHERE Month(Date) = 3;
SELECT AVG(Balance) FROM Accounts;
COMMIT;
-- Even if other transactions commit during this, our report is from the snapshot Example 2 β E-commerce: READ COMMITTED is Fine
-- Product availability check - always want to see latest committed stock
SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;
SELECT Stock FROM Products WHERE Product_ID = 45;
-- If another session just committed a stock update, we see it immediately (good!)- Using SERIALIZABLE everywhere "to be safe": This destroys database throughput. Web applications under SERIALIZABLE cannot handle concurrent users. Use REPEATABLE READ (default) for safety and performance.
- Assuming READ UNCOMMITTED is okay for "read-only" use: Even read-only operations can make wrong decisions based on dirty data. Never use READ UNCOMMITTED for business logic.
- Not understanding that MySQL's REPEATABLE READ also prevents Phantoms: MySQL's MVCC implementation prevents phantom reads at REPEATABLE READ level β this is better than the ANSI SQL standard requires. Don't upgrade to SERIALIZABLE just to prevent phantoms.
- Stick with REPEATABLE READ (default) for 99% of applications β MySQL chose it as default for good reason.
- Use READ COMMITTED if your application is "read-heavy" and doesn't need consistent snapshots (e.g., live dashboards).
- Use SERIALIZABLE only for critical financial calculations that require absolute consistency, and be prepared to limit concurrent access.
- Never use READ UNCOMMITTED in production β there is no legitimate use case for reading uncommitted data in a business system.
- Task 1: What is a "Dirty Read"? Write a timeline showing how it can occur and what harm it could cause in a bank balance scenario.
- Task 2: MySQL's default isolation level is REPEATABLE READ. What problem does this specifically prevent compared to READ COMMITTED? Give a concrete example.
- Task 3: A team argues about using SERIALIZABLE for their e-commerce site "to prevent any data issues." Why is this a bad idea, and what should they use instead?