MySQL 学习笔记:四种事务隔离级别与三种读异常
一、事务隔离级别
MySQL 有四种事务隔离级别,主要用于控制多个事务并发执行时的数据可见性。
✅ 表示可以防止;❌ 表示可能发生。
MySQL InnoDB 的 RR 通过 MVCC 使普通快照读避免幻读,通过 Next-Key Lock 等锁机制防止适用场景下当前读的幻读,但混用快照读和当前读时仍可能观察到不同结果。
MySQL InnoDB 默认使用 RR(可重复读)。
二、三种读异常
1. 脏读(Dirty Read)
定义:一个事务读取到了另一个事务尚未提交的数据。
假设账户余额为 1000 元。
事务 B 读取到了尚未提交的 500,这就是脏读。
注意:即使事务 A 最终提交成功,事务 B 提前读取了未提交数据,仍然属于脏读。
解决方式:RC 及更高级别。
2. 不可重复读(Non-Repeatable Read)
定义:同一个事务内,两次读取同一条记录,读取到的字段值不同。
假设余额为 1000 元。
事务 A 两次读取同一条记录,第一次是 1000,第二次是 500。
这是不可重复读。
解决方式:RR 及更高级别。
在 InnoDB RR 中,同一事务内的普通快照读通常复用第一次一致性读创建的 Read View,所以能够保持读取结果一致。
3. 幻读(Phantom Read)
定义:同一个事务内,两次按照相同条件查询,发现符合条件的记录集合发生变化,典型情况是其他事务插入了新记录。
例如:
SELECT * FROM user WHERE age > 20;事务 A 发现符合条件的记录多出了一条,就像出现了“幻影”。
解决方式:Serializable 可以防止幻读。MySQL InnoDB 的 RR 也通过 MVCC 和间隙锁、Next-Key Lock 等机制,在相应读取场景下避免幻读。
三、四种隔离级别分别解决什么问题?
RC 与 RR 的核心区别
对于普通快照读:
RC: 每条 SELECT 通常创建新的 Read View,因此可以读取其他事务最新提交的数据。
RR: 第一次一致性读创建 Read View,后续一致性读通常复用,因此能保证可重复读。
注意:SELECT ... FOR UPDATE、UPDATE、DELETE 属于当前读或需要读取当前版本的操作,不能直接套用上述快照读规则。
四、面试总结
问题 1:什么是脏读?
读取到了其他事务尚未提交的数据。重点是“未提交”,而不是数据与最终结果是否一致。
问题 2:脏读和不可重复读有什么区别?
脏读关注数据是否提交;不可重复读关注同一事务内两次读取同一条记录,结果是否发生变化。
问题 3:不可重复读和幻读有什么区别?
不可重复读主要关注同一条记录的字段值变化;幻读主要关注符合查询条件的记录集合发生变化。
问题 4:为什么 RR 可以实现可重复读?
因为 InnoDB 通过 MVCC 和 Read View 实现一致性读。在 RR 下,同一事务的普通快照读通常复用同一个 Read View。
问题 5:MySQL 默认隔离级别是什么?
InnoDB 默认使用 RR(可重复读)。
五、重点记忆
脏读: 读到了别人还没提交的数据。
不可重复读: 同一事务,两次读取同一条记录,值发生变化。
幻读: 同一事务,两次相同条件查询,符合条件的记录集合发生变化。
RC: 解决脏读。
RR: 解决不可重复读,InnoDB 还能在常见场景下避免幻读。
Serializable: 隔离最严格,防止三种读异常。
一句话总结:脏读看是否提交,不可重复读看记录值变化,幻读看记录集合变化。
