Summary: in this tutorial, you will learn about MySQL transactions and how to use the START TRANSACTION
, COMMIT
and ROLLBACK
statements to manage transactions in MySQL.
Introduction to MySQL transactions
In the database world, a transaction is a sequence of one or more SQL statements that are executed as a single unit of work.
Transactions allow you to ensure the integrity of data by enabling a set of operations to be either fully completed or fully rolled back in case of an error.
MySQL supports transactions via the START TRANSACTION
, COMMIT
, and ROLLBACK
statements:
START TRANSACTION
– Mark the beginning of a transaction. Note that theBEGIN
orBEGIN
WORK
are the aliases of theSTART TRANSACTION
.COMMIT
– Apply the changes of a transaction to the database.ROLLBACK
– Undo the changes of a transaction by reverting the database to the state before the transaction starts.
By default, when you execute an SQL statement, MySQL automatically wraps it in a transaction and commits the transaction automatically.
To instruct MySQL to not start a transaction implicitly and commit the changes automatically, you set the value of the autocommit
variable to 0
or OFF
:
SET autocommit = OFF;
Code language: SQL (Structured Query Language) (sql)
Or:
SET autocommit = 0;
Code language: SQL (Structured Query Language) (sql)
To enable the auto-commit mode, you set the value of the autocommit
variable to 1
or ON
:
SET autocommit = 1;
Code language: SQL (Structured Query Language) (sql)
Or:
SET autocommit = ON;
Code language: SQL (Structured Query Language) (sql)
Basic MySQL transactions example
1) Setting up sample tables
First, connect to the MySQL server:
mysql -u root -p
Code language: SQL (Structured Query Language) (sql)
Second, create a database called banks
and a table named users
:
CREATE DATABASE banks;
USE banks;
CREATE TABLE users (
id INT PRIMARY KEY,
username VARCHAR(255) NOT NULL,
email VARCHAR(255)
);
Code language: SQL (Structured Query Language) (sql)
2) MySQL COMMIT example
First, start a transaction that inserts a new row into the users
table and updates the email for the user:
START TRANSACTION;
INSERT INTO users (id, username)
VALUES (1, 'john');
UPDATE users
SET email = '[email protected]'
WHERE id = 1;
Code language: SQL (Structured Query Language) (sql)
Second, retrieve data from the users
table:
SELECT * FROM users;
Code language: SQL (Structured Query Language) (sql)
Output:
+----+----------+----------------------+
| id | username | email |
+----+----------+----------------------+
| 1 | john | [email protected] |
+----+----------+----------------------+
1 row in set (0.00 sec)
Code language: SQL (Structured Query Language) (sql)
The output shows that the users
table has a row but it is only visible to the current session, not other sessions.
If you open another session and query data from the users
table, you will not see any rows in the users
table. The reason is that the transaction in the first session has not been committed.
Fifth, commit the transaction:
COMMIT;
Code language: SQL (Structured Query Language) (sql)
The COMMIT
statement applies all the changes made during the transaction, making them permanent and visible to other database sessions.
If you open the second session, you will be able to see the data from the users
table.
3) MySQL ROLLBACK example
First, start a transaction:
START TRANSACTION;
Code language: SQL (Structured Query Language) (sql)
Second, insert a new row into the users
table and update the email
for the user:
INSERT INTO users (id, username)
VALUES (2, 'jane');
UPDATE users
SET email = '[email protected]'
WHERE id = 2;
Code language: SQL (Structured Query Language) (sql)
Third, roll back the transaction:
ROLLBACK;
Code language: SQL (Structured Query Language) (sql)
The ROLLBACK
statement undoes all the changes made during the transaction, reverting the database to its state before the transaction started.
Finally, select data from the users
table:
SELECT * FROM users;
Code language: SQL (Structured Query Language) (sql)
Output:
+----+----------+----------------------+
| id | username | email |
+----+----------+----------------------+
| 1 | john | [email protected] |
+----+----------+----------------------+
1 row in set (0.00 sec)
Code language: SQL (Structured Query Language) (sql)
The output shows that the transaction has been rolled back so there is no new row in the users
table.
Using MySQL transactions in Stored Procedures
1) Setting up sample tables
First, change the current database to banks
:
CREATE DATABASE banks;
Code language: SQL (Structured Query Language) (sql)
Second, create a new table called accounts
to store the account holders and balances:
CREATE TABLE accounts (
account_id INT AUTO_INCREMENT PRIMARY KEY ,
account_holder VARCHAR(255) NOT NULL,
balance DECIMAL(10, 2) NOT NULL
);
Code language: SQL (Structured Query Language) (sql)
Third, create a table called transactions
to store the transactions between accounts:
CREATE TABLE transactions (
transaction_id INT AUTO_INCREMENT PRIMARY KEY,
account_id INT NOT NULL,
amount DECIMAL(10, 2) NOT NULL,
transaction_type ENUM('DEPOSIT', 'WITHDRAWAL') NOT NULL,
FOREIGN KEY (account_id) REFERENCES accounts(account_id)
);
Code language: SQL (Structured Query Language) (sql)
Finally, insert two rows into the accounts
table:
INSERT INTO accounts (account_holder, balance)
VALUES ('John Doe', 1000.00),
('Jane Doe', 500.00);
Code language: SQL (Structured Query Language) (sql)
Transferring money between two accounts
The following creates a stored procedure that transfers money between two accounts:
DELIMITER //
CREATE PROCEDURE transfer(
IN sender_id INT,
IN receiver_id INT,
IN amount DECIMAL(10,2)
)
BEGIN
DECLARE rollback_message VARCHAR(255) DEFAULT 'Transaction rolled back: Insufficient funds';
DECLARE commit_message VARCHAR(255) DEFAULT 'Transaction committed successfully';
-- Start the transaction
START TRANSACTION;
-- Attempt to debit money from account 1
UPDATE accounts SET balance = balance - amount WHERE account_id = sender_id;
-- Attempt to credit money to account 2
UPDATE accounts SET balance = balance + amount WHERE account_id = receiver_id;
-- Check if there are sufficient funds in account 1
-- Simulate a condition where there are insufficient funds
IF (SELECT balance FROM accounts WHERE account_id = sender_id) < 0 THEN
-- Roll back the transaction if there are insufficient funds
ROLLBACK;
SIGNAL SQLSTATE '45000'
SET MESSAGE_TEXT = rollback_message;
ELSE
-- Log the transactions if there are sufficient funds
INSERT INTO transactions (account_id, amount, transaction_type) VALUES (sender_id, -amount, 'WITHDRAWAL');
INSERT INTO transactions (account_id, amount, transaction_type) VALUES (receiver_id, amount, 'DEPOSIT');
-- Commit the transaction
COMMIT;
SELECT commit_message AS 'Result';
END IF;
END //
DELIMITER ;
Code language: SQL (Structured Query Language) (sql)
The transfer stored procedure transfers an amount between two accounts: sender and receiver. It has three parameters:
sender_id
– the sender id.receiver_id
– the receiver id.amount
– the amount that will be transferred between the two accounts.
How it works.
First, start the transaction using the START TRANSACTION
statement:
START TRANSACTION;
Code language: SQL (Structured Query Language) (sql)
Second, increase the balance of the sender and decrease the balance of the receiver:
UPDATE
accounts
SET
balance = balance - amount
WHERE
account_id = sender_id;
UPDATE
accounts
SET
balance = balance + amount
WHERE
account_id = receiver_id;
Code language: SQL (Structured Query Language) (sql)
Third, roll back the transaction if the balance of the sender’s account is not sufficient and also issue an error message:
IF (SELECT balance FROM accounts WHERE account_id = sender_id) < 0 THEN
ROLLBACK;
SIGNAL SQLSTATE '45000'
SET MESSAGE_TEXT = rollback_message;
Code language: SQL (Structured Query Language) (sql)
Otherwise, add two rows to the transactions
table and apply the changes to the database by committing the transaction (in the ELSE
branch):
INSERT INTO transactions (account_id, amount, transaction_type) VALUES (1, -amount, 'WITHDRAWAL');
INSERT INTO transactions (account_id, amount, transaction_type) VALUES (2, amount, 'DEPOSIT');
COMMIT;
SELECT commit_message AS 'Result';
Code language: SQL (Structured Query Language) (sql)
Calling the transfer stored procedure
First, retrieve the balances of the accounts:
SELECT * FROM accounts;
Code language: SQL (Structured Query Language) (sql)
Output:
+------------+----------------+---------+
| account_id | account_holder | balance |
+------------+----------------+---------+
| 1 | John Doe | 1000.00 |
| 2 | Jane Doe | 500.00 |
+------------+----------------+---------+
2 rows in set (0.00 sec)
Code language: SQL (Structured Query Language) (sql)
Second, transfer 100 from account id 1 to account id 2:
CALL transfer(1,2,100);
Code language: SQL (Structured Query Language) (sql)
Output:
+------------------------------------+
| Result |
+------------------------------------+
| Transaction committed successfully |
+------------------------------------+
1 row in set (0.01 sec)
Query OK, 0 rows affected (0.01 sec)
Code language: SQL (Structured Query Language) (sql)
Since account id 1 has sufficient funds, the transaction succeeded.
Third, review the balances of the accounts:
SELECT
*
FROM
accounts
WHERE
account_id IN (1, 2);
Code language: SQL (Structured Query Language) (sql)
Output:
+------------+----------------+---------+
| account_id | account_holder | balance |
+------------+----------------+---------+
| 1 | John Doe | 900.00 |
| 2 | Jane Doe | 600.00 |
+------------+----------------+---------+
2 rows in set (0.00 sec)
Code language: SQL (Structured Query Language) (sql)
The output indicates that account id 1 has a balance of 900 and account id 2 has a balance of 600, which is correct.
SELECT * FROM transactions;
Code language: SQL (Structured Query Language) (sql)
Output:
+----------------+------------+---------+------------------+
| transaction_id | account_id | amount | transaction_type |
+----------------+------------+---------+------------------+
| 1 | 1 | -100.00 | WITHDRAWAL |
| 2 | 2 | 100.00 | DEPOSIT |
+----------------+------------+---------+------------------+
2 rows in set (0.00 sec)
Code language: SQL (Structured Query Language) (sql)
The transactions
table also has two rows that record the transfer.
Fourth, attempt to transfer 1000 from account id 1 to account id 2:
CALL transfer(1,2,1000);
Code language: SQL (Structured Query Language) (sql)
Output:
ERROR 1644 (45000): Transaction rolled back: Insufficient funds
Code language: SQL (Structured Query Language) (sql)
Because account id 1 does not have sufficient funds, the transaction was rolled back. Also, the balances of both accounts were reverted:
SELECT * FROM accounts;
Code language: SQL (Structured Query Language) (sql)
Output:
+------------+----------------+---------+
| account_id | account_holder | balance |
+------------+----------------+---------+
| 1 | John Doe | 900.00 |
| 2 | Jane Doe | 600.00 |
+------------+----------------+---------+
2 rows in set (0.00 sec)
Code language: SQL (Structured Query Language) (sql)
Summary
- A transaction is a sequence of SQL statements that is executed as a single unit of work.
- Use the
START
TRANSACTION
statement to start a transaction. - Use the
COMMIT
statement to apply the changes made during the transaction to the database. - Use the
ROLLBACK
statement to roll back the changes made during the transaction and revert the state of the database before the transaction starts.