Transactions, ACID & isolation levels
START TRANSACTION, COMMIT, ROLLBACK, savepoints, autocommit, ACID and the four isolation levels.
Transferring ₹500 from Asha to Rohan takes two updates: subtract from one account, add to the other. If the server crashes between them, money vanishes. A transaction groups statements into a single unit that either fully happens or doesn't happen at all. Transactions also control what concurrent users can see of each other's unfinished work.
Sample data#
Transactions need a transactional storage engine. InnoDB, the default, is one. MyISAM isn't, and silently ignores ROLLBACK.
COMMIT and ROLLBACK#
START TRANSACTION(orBEGIN) opens a transaction.COMMITmakes every change permanent and visible to others.ROLLBACKthrows all of the changes away:
In application code, the pattern is always: begin, run the statements, commit if everything succeeded, roll back on any error.
Autocommit#
By default MySQL runs in autocommit mode: every statement outside an explicit transaction is its own transaction and commits immediately. That's why a single UPDATE sticks even without COMMIT.
SET autocommit = 0; changes this for your session, so that changes stay pending until you COMMIT. Be careful: forgetting to commit leaves locks held and work invisible to everyone else. Prefer explicit START TRANSACTION blocks.
Savepoints#
A savepoint marks a point inside a transaction that you can roll back to without abandoning the whole thing:
The failing statement was rejected by the CHECK constraint. A failed statement is rolled back on its own, but the transaction stays open, so your code decides what to do next. Here we kept the 100 fee and committed.
Implicit commits#
Some statements commit the current transaction automatically, and can't be rolled back themselves: DDL (CREATE, ALTER, DROP, TRUNCATE, RENAME), user management (CREATE USER, GRANT), LOCK TABLES and a few others. Never mix schema changes into a data transaction and expect ROLLBACK to undo them.
ACID#
Isolation levels#
When transactions run at the same time, three classic anomalies can occur:
- Dirty read: seeing another transaction's uncommitted change (which may later be rolled back).
- Non-repeatable read: reading the same row twice in one transaction and getting different values, because someone committed an update in between.
- Phantom read: running the same range query twice and getting new rows, because someone inserted in between.
SQL defines four isolation levels:
*InnoDB's REPEATABLE READ uses a consistent snapshot for ordinary SELECTs, so they don't see phantoms. Locking reads (SELECT ... FOR UPDATE) and writes see the latest data, and InnoDB uses gap locks to block phantoms there.
Seeing REPEATABLE READ in action
Open two mysql sessions side by side and run these steps in order:
InnoDB achieves this with MVCC (multi-version concurrency control). Instead of blocking readers, it keeps older row versions in the undo log and shows each transaction the version that matches its snapshot. That's why, in InnoDB, readers don't block writers and writers don't block readers.
Which level should you use?
- REPEATABLE READ (default) is a good general choice and gives stable reports within a transaction.
- READ COMMITTED is popular for high-concurrency OLTP apps (and is PostgreSQL's and Oracle's default). It takes fewer gap locks, so there are fewer deadlocks, and each statement sees the latest committed data.
- SERIALIZABLE turns plain
SELECTs into locking reads. It's the safest and the slowest. - READ UNCOMMITTED is almost never appropriate.
Isolation levels don't protect a read-then-write pattern on their own. "Read the balance in the app, then write balance − 500" can still lose updates under concurrency. Use an atomic UPDATE ... SET balance = balance - 500 WHERE balance >= 500, or lock the row with SELECT ... FOR UPDATE (next lesson).
Best practices#
- Keep transactions short. Never wait for user input or call slow external APIs inside one, because locks and old row versions pile up.
- Always handle errors with a rollback, and close transactions in a
finallyblock or with your framework's transaction helper. - Make retries safe. Deadlocks and lock-wait timeouts happen under load, so be ready to retry the whole transaction.
- Do big batch jobs in chunks (for example 1,000 rows per transaction) rather than one huge transaction.
What's next#
Isolation levels describe what you see. Locks decide who waits for whom. Next: row locks, FOR UPDATE, SKIP LOCKED and deadlocks.
Check your understanding
Quick quiz
1.What does the 'A' in ACID guarantee?
2.What is InnoDB's default transaction isolation level?
3.You run
START TRANSACTION; DELETE FROM t; CREATE TABLE x (id INT); ROLLBACK;. What happens to the deleted rows?
Finished reading?
Mark this lesson complete to track your progress.