Transaction Control Language (TCL) gives you a safety net for your DML operations. It lets you group multiple SQL statements into one atomic unit of work β either all succeed together, or none of them do. This is the feature that protects bank transfers, e-commerce checkouts, and every critical operation from partial failures.
| Command | What It Does |
|---|---|
START TRANSACTION / BEGIN |
Marks the beginning of a safe unit of work. Pauses autocommit. |
COMMIT |
Permanently saves all changes made since START TRANSACTION. |
ROLLBACK |
Discards all changes made since START TRANSACTION. Restores previous state. |
SAVEPOINT name |
Creates a named checkpoint inside a transaction. |
ROLLBACK TO name |
Rolls back only to the named savepoint (not the whole transaction). |
RELEASE SAVEPOINT name |
Removes a savepoint (optional cleanup). |
- Human Error Protection: You accidentally run
DELETE FROM Orderswithout aWHEREclause. If you were inside a transaction, just typeROLLBACKand every row comes back instantly. - Logical Dependency: A bank transfer must debit Account A AND credit Account B. If only the debit succeeds, money disappears. Wrapping both in a transaction ensures they either both succeed or both fail together.
- Integrity During Crashes: Combined with ACID properties (Topic 15.1), if the server crashes mid-transaction, MySQL uses its Redo/Undo logs to either complete or roll back the transaction cleanly on restart.
By default, MySQL runs in Autocommit Mode:
SELECT @@autocommit; -- Returns 1 (ON)In autocommit mode, every single SQL statement is immediately and permanently committed to disk. There is no undo.
You have two ways to take control:
Option 1: Use START TRANSACTION (Recommended β Explicit)
START TRANSACTION; -- Pauses autocommit just for this block
UPDATE Accounts SET Balance = Balance - 100 WHERE ID = 1;
UPDATE Accounts SET Balance = Balance + 100 WHERE ID = 2;
COMMIT; -- Now both updates are permanentOption 2: Turn off autocommit for the session
SET autocommit = 0; -- All future statements need manual COMMIT
UPDATE Products SET Price = 500 WHERE ID = 3;
COMMIT;
SET autocommit = 1; -- Always turn it back on!START TRANSACTION;
-- Step 1: Debit sender
UPDATE Accounts SET Balance = Balance - 1000 WHERE Account_ID = 101;
-- Step 2: Credit receiver
UPDATE Accounts SET Balance = Balance + 1000 WHERE Account_ID = 202;
-- Check: Did both work correctly?
SELECT Balance FROM Accounts WHERE Account_ID IN (101, 202);
COMMIT; -- Looks good β make it permanent!
-- OR:
-- ROLLBACK; -- Something went wrong β undo everything!START TRANSACTION;
INSERT INTO Orders (Customer_ID, Total) VALUES (5, 250.00);
SAVEPOINT after_order; -- β Checkpoint: order is saved here
INSERT INTO Order_Items (Order_ID, Product_ID, Qty) VALUES (LAST_INSERT_ID(), 12, 2);
SAVEPOINT after_items; -- β Checkpoint: items are saved here
INSERT INTO Invoices (Order_ID, Due_Date) VALUES (LAST_INSERT_ID(), '2024-12-31');
-- Something goes wrong in invoices...
ROLLBACK TO after_items; -- β Undo only the invoice, keep order + items β
COMMIT; -- Permanently save: order + items (invoice is discarded)START TRANSACTION;
-- 1. Reduce stock
UPDATE Products SET Stock = Stock - 2 WHERE Product_ID = 45;
-- 2. Check if stock went negative (data validation)
SELECT Stock FROM Products WHERE Product_ID = 45 INTO @new_stock;
IF @new_stock < 0 THEN
ROLLBACK;
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'Out of stock!';
END IF;
-- 3. Create the order
INSERT INTO Orders (Customer_ID, Status, Total) VALUES (88, 'Pending', 199.98);
-- 4. Create shipping record
INSERT INTO Shipments (Order_ID, Address) VALUES (LAST_INSERT_ID(), '42 Baker St');
COMMIT; -- All 4 steps succeeded β commit everything atomically- Leaving transactions open too long: While a transaction is open, InnoDB holds Row Locks on every row you touched. Other database connections that try to update those same rows will be blocked until you
COMMITorROLLBACK. Long-running transactions can freeze entire parts of your application. - Forgetting TCL doesn't protect DDL:
COMMITandROLLBACKonly protect DML (INSERT,UPDATE,DELETE). DDL commands likeCREATE TABLE,DROP TABLE, andALTER TABLEalways auto-commit immediately in MySQL β they cannot be rolled back. - Not handling errors in application code: If your Python/Node.js app throws an exception mid-transaction, you must catch it and explicitly call
ROLLBACK. Otherwise the transaction might stay open and locks accumulate.
| Command Type | Can Be Rolled Back? | Examples |
|---|---|---|
| DML | β Yes | INSERT, UPDATE, DELETE |
| DDL | β No (auto-commits) | CREATE TABLE, DROP TABLE, ALTER TABLE, TRUNCATE |
| DCL | β No | GRANT, REVOKE |
- Wrap ALL multi-step operations in transactions: Any time your operation touches more than one table or row, use
START TRANSACTION. - Use SAVEPOINT for long batch operations: If you're processing 1,000 rows in a loop, set a SAVEPOINT every 100 rows so you don't have to restart entirely if something fails at row 850.
- Keep transactions as short as possible: Open β Work β Commit. The longer a transaction lives, the more it holds locks and blocks other users.
- Task 1: What is the difference between
COMMITandROLLBACK? Write a complete transaction that transfers βΉ500 fromAccount_ID = 1toAccount_ID = 2, and only commits if bothUPDATEstatements succeed. - Task 2: Why can't you
ROLLBACKaDROP TABLEcommand even if you're inside aSTART TRANSACTIONblock? - Task 3: Write a script that starts a transaction, inserts a record into a
Logstable, creates aSAVEPOINT, inserts a second record, and then rolls back only the second insert usingROLLBACK TO SAVEPOINT.