MySQL 事务(Transaction)是一组不可分割的数据库操作,要么全部执行成功,要么全部执行失败,是保证数据一致性、安全性的核心机制。
最典型的场景:银行转账(A扣钱、B加钱),必须两个操作同时成功/失败,不能出现A扣了钱B没收到的情况。
一、事务核心特性:ACID
事务必须严格满足 ACID 四大特性,这是事务的灵魂:
1. Atomicity(原子性)
- 定义:事务是最小执行单元,要么全部成功,要么全部回滚失败,不允许中间状态。
- 例子:转账 100 元,扣钱和加钱必须一起成功/一起失败。
2. Consistency(一致性)
- 定义:事务执行前后,数据库的完整性约束不变,数据始终合法。
- 例子:转账前后,两个人的总金额不变。
3. Isolation(隔离性)
- 定义:多个事务并发执行时,互相不可干扰,一个事务看不到另一个事务的中间状态。
- 由事务隔离级别控制。
4. Durability(持久性)
- 定义:事务一旦提交(COMMIT),数据永久生效,即使数据库崩溃也不会丢失。
二、事务的基本语法
MySQL 默认自动提交事务(autocommit=1),手动控制事务语法如下:
-- 1. 开启事务
START TRANSACTION; -- 或 BEGIN;
-- 2. 执行多条 SQL 操作
UPDATE account SET money = money - 100 WHERE name = 'A';
UPDATE account SET money = money + 100 WHERE name = 'B';
-- 3. 提交事务(所有操作永久生效)
COMMIT;
-- 4. 回滚事务(所有操作全部撤销,回到执行前状态)
ROLLBACK;
重要:自动提交开关
-- 查看自动提交状态
SELECT @@autocommit; -- 1=自动提交 0=手动提交
-- 关闭自动提交(当前会话生效)
SET autocommit = 0;
三、并发事务带来的问题
如果不控制事务隔离性,多个事务同时操作同一份数据,会出现 4 类问题:
1. 脏读(Dirty Read)
一个事务读到了另一个事务未提交的修改,如果对方回滚,数据就是无效的。
2. 不可重复读(Non-Repeatable Read)
同一个事务内,多次查询同一行数据,结果不一致(被其他事务修改并提交了)。
3. 幻读(Phantom Read)
同一个事务内,多次查询符合条件的记录总数不一致(其他事务插入/删除了数据)。
4. 丢失更新(Lost Update)
两个事务同时修改同一数据,后提交的覆盖先提交的修改,导致数据丢失。
四、事务隔离级别(重点)
MySQL InnoDB 引擎提供 4 种隔离级别,用来解决上面的并发问题,级别越高越安全、性能越低。
| 隔离级别 | 脏读 | 不可重复读 | 幻读 | 说明 |
|---|---|---|---|---|
| READ UNCOMMITTED(读未提交) | ✅ 允许 | ✅ 允许 | ✅ 允许 | 最低级别,基本不用 |
| READ COMMITTED(读已提交) | ❌ 禁止 | ✅ 允许 | ✅ 允许 | 互联网常用 |
| REPEATABLE READ(可重复读) | ❌ 禁止 | ❌ 禁止 | ❌ 禁止 | MySQL 默认级别 |
| SERIALIZABLE(串行化) | ❌ 禁止 | ❌ 禁止 | ❌ 禁止 | 完全串行,性能极低 |
查看/设置隔离级别
-- 查看当前隔离级别
SELECT @@transaction_isolation;
-- 设置当前会话隔离级别
SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;
五、事务实现原理(简版)
InnoDB 依靠三大机制保证 ACID:
- redo log(重做日志):保证持久性,崩溃恢复数据
- undo log(回滚日志):保证原子性,回滚时撤销操作
- 锁 + MVCC(多版本并发控制):保证隔离性,实现高并发读写
六、事务使用注意事项
- 事务要短小精悍 长事务会锁定资源、占用日志空间,导致数据库性能下降。
- 避免在事务中做无关操作 不要在事务里调用外部接口、sleep、复杂计算,拉长事务执行时间。
- 提交/回滚必须明确 不要忘记 COMMIT 或 ROLLBACK,否则会导致锁不释放。
- 只在需要数据一致性时使用 单条 SQL 不需要手动开启事务(MySQL 自动封装为事务)。
总结
- 事务 = 一组不可分割的 SQL,要么全成,要么全败
- 核心 ACID:原子、一致、隔离、持久
- 并发问题:脏读、不可重复读、幻读
- 4 种隔离级别:MySQL 默认 可重复读(RR),互联网常用 读已提交(RC)
- 语法:
BEGIN→ 操作 →COMMIT/ROLLBACK