MySQL 事务(Transaction)详解
MySQL 事务(Transaction)详解
1. 什么是事务?
事务(Transaction)是一组要么全部执行,要么全部回滚的 SQL 语句,用于保证数据一致性。事务一般用于银行转账、订单支付等操作,确保多个步骤要么全部成功,要么全部失败。
事务的特点(ACID):
- 原子性(Atomicity):事务是一个不可分割的最小操作单位,要么全部执行,要么全部回滚。
- 一致性(Consistency):事务执行后,数据库必须保持一致状态。
- 隔离性(Isolation):多个事务并发执行时,相互之间不会影响。
- 持久性(Durability):事务提交后,对数据库的更改是永久性的。
2. 事务的基本操作
在 MySQL 中,事务通常用 START TRANSACTION
或 BEGIN
开始,COMMIT
提交,ROLLBACK
回滚:
-- 开启事务
START TRANSACTION;
-- 执行 SQL 语句
UPDATE accounts SET balance = balance - 100 WHERE user_id = 1;
UPDATE accounts SET balance = balance + 100 WHERE user_id = 2;
-- 提交事务(数据永久生效)
COMMIT;
如果中途发生错误,可以回滚:
-- 开启事务
START TRANSACTION;
-- 执行 SQL 语句
UPDATE accounts SET balance = balance - 100 WHERE user_id = 1;
-- 发生错误,回滚事务
ROLLBACK;
3. 事务的隔离级别
MySQL 事务的隔离级别影响并发事务的执行方式,常见隔离级别:
隔离级别 | 脏读 | 不可重复读 | 幻读 | 默认值 |
---|---|---|---|---|
READ UNCOMMITTED(读未提交) | ❌ 可能 | ❌ 可能 | ❌ 可能 | ❌ |
READ COMMITTED(读已提交) | ✅ 避免 | ❌ 可能 | ❌ 可能 | ❌ |
REPEATABLE READ(可重复读) | ✅ 避免 | ✅ 避免 | ❌ 可能 | ✅(MySQL 默认) |
SERIALIZABLE(串行化) | ✅ 避免 | ✅ 避免 | ✅ 避免 | ❌ |
如何设置隔离级别?
SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ;
4. 事务的常见问题
(1)脏读(Dirty Read)
发生在 READ UNCOMMITTED
级别:一个事务能读取另一个未提交事务的数据,如果对方回滚,读取的数据就是无效的。
-- 事务 A
START TRANSACTION;
UPDATE accounts SET balance = 500 WHERE user_id = 1;
-- 此时事务 A 还未提交
-- 事务 B
SELECT balance FROM accounts WHERE user_id = 1; -- 读取到了未提交的值
✅ 解决方案:使用 READ COMMITTED
以上隔离级别。
(2)不可重复读(Non-Repeatable Read)
发生在 READ COMMITTED
级别:同一个事务多次读取数据,发现数据不一致(另一事务修改了数据并提交)。
-- 事务 A
START TRANSACTION;
SELECT balance FROM accounts WHERE user_id = 1; -- 读取值 500
-- 事务 B(修改后提交)
UPDATE accounts SET balance = 600 WHERE user_id = 1;
COMMIT;
-- 事务 A(再次读取)
SELECT balance FROM accounts WHERE user_id = 1; -- 发现变成 600
✅ 解决方案:使用 REPEATABLE READ
以上隔离级别。
(3)幻读(Phantom Read)
发生在 REPEATABLE READ
级别:事务中多次查询,发现新增的行。
-- 事务 A
START TRANSACTION;
SELECT COUNT(*) FROM orders WHERE user_id = 1; -- 10 条数据
-- 事务 B(插入新数据并提交)
INSERT INTO orders(user_id, amount) VALUES (1, 100);
COMMIT;
-- 事务 A(再次查询)
SELECT COUNT(*) FROM orders WHERE user_id = 1; -- 发现 11 条数据
✅ 解决方案:使用 SERIALIZABLE
级别,防止新数据插入。
5. InnoDB 与 MyISAM 事务支持
存储引擎 | 事务支持 | 适用场景 |
---|---|---|
InnoDB | ✅ 支持事务 | 适合高并发、数据一致性要求高的系统,如金融、订单 |
MyISAM | ❌ 不支持事务 | 适合读取操作多的场景,如 CMS 系统 |
如何查看表的存储引擎?
SHOW TABLE STATUS WHERE Name = 'my_table';
6. MySQL 事务最佳实践
- 尽量使用 InnoDB,保证事务支持。
- 缩小事务范围,避免长时间锁表影响性能。
- 避免事务嵌套,减少锁竞争。
- 使用索引优化查询,减少锁的范围,提高并发效率。
- 发生错误时记得
ROLLBACK
,确保数据一致性。 - 适当选择隔离级别,根据业务需求权衡并发性和数据一致性。
7. 事务相关的 SQL 语句
操作 | SQL 语句 |
---|---|
开启事务 | START TRANSACTION; 或 BEGIN; |
提交事务 | COMMIT; |
回滚事务 | ROLLBACK; |
设置隔离级别 | SET TRANSACTION ISOLATION LEVEL REPEATABLE READ; |
查看当前事务隔离级别 | SELECT @@TRANSACTION_ISOLATION; |
8. 总结
- 事务保证 ACID,保证数据库的一致性。
- MySQL 事务隔离级别决定数据并发访问时的行为,
REPEATABLE READ
是 MySQL 默认隔离级别。 - 事务的三大问题:脏读、不可重复读、幻读,可通过不同的隔离级别解决。
- InnoDB 支持事务,MyISAM 不支持。
- 务必在事务结束后
COMMIT
或ROLLBACK
,防止事务长时间占用资源。