极高 进阶
事务隔离级别#
一句话答案#
四级隔离:读未提交(脏读)→读已提交(不可重复读)→可重复读(RR,MySQL 默认,MVCC+间隙锁解决幻读)→串行化。
核心要点
三大并发问题:
- 脏读(Dirty Read):读到了另一个事务未提交的数据,如果那个事务回滚,读到的就是”脏数据”
- 不可重复读(Non-repeatable Read):同一事务内,多次读同一行数据,结果不同(另一事务修改并提交了)
- 幻读(Phantom Read):同一事务内,两次按条件查询,结果集行数不同(另一事务插入或删除了行)
四种隔离级别(由低到高):
| 隔离级别 | 脏读 | 不可重复读 | 幻读 | 性能 |
|---|---|---|---|---|
| READ UNCOMMITTED(读未提交) | ✅ 解决❌ | ✅ 存在 | ✅ 存在 | 最高 |
| READ COMMITTED(读已提交) | ✅ 解决 | ✅ 存在 | ✅ 存在 | 高 |
| REPEATABLE READ(可重复读) | ✅ 解决 | ✅ 解决 | ⚠️ 基本解决 | 中 |
| SERIALIZABLE(串行化) | ✅ 解决 | ✅ 解决 | ✅ 解决 | 最低 |
⚠️ InnoDB 的 REPEATABLE READ 通过 MVCC + Next-Key Lock,实际上解决了大多数幻读场景,这是与标准 SQL 定义的区别。
MySQL 默认:REPEATABLE READ
面试回答(2分钟版)
SQL 标准定义四种隔离级别,从低到高依次是读未提交、读已提交、可重复读和串行化。对应三种并发问题:脏读是读到其他事务未提交的数据,不可重复读是同一事务多次读同一行结果不同,幻读是两次范围查询返回行数不同。读未提交三个问题都存在,读已提交解决脏读,可重复读解决脏读和不可重复读,串行化全部解决但并发最差。MySQL 默认 RR 级别,因为早期 binlog 用 STATEMENT 格式时 RC 可能导致主从不一致。InnoDB 的 RR 比标准更强:快照读通过 MVCC 保证同一事务内多次读取一致,当前读通过 Next-Key Lock 即间隙锁加记录锁防止幻读,解决了大部分幻读场景。但严格来说 RR 并非完全杜绝幻读,先快照读再当前读的混合场景下仍可能出现不一致。
追问与易错
追问方向:
- “MySQL 默认隔离级别是什么?为什么选 RR?”→ 默认 REPEATABLE READ;历史原因是早期 binlog 用 STATEMENT 格式时 RC 级别可能导致主从执行顺序不同数据不一致,RR + 间隙锁保证了 binlog 回放的确定性
- “RR 下还会有幻读吗?举个例子?”→ 快照读通过 MVCC 不会幻读;但混合使用快照读和当前读时可能出现:先 SELECT 查无数据,再 INSERT 发现主键冲突(其他事务已插入),再 SELECT 仍查不到——表现为”幻行”
- “如何在代码中设置隔离级别?”→ Spring 中用 @Transactional(isolation = Isolation.READ_COMMITTED) 注解设置;也可通过 SET SESSION TRANSACTION ISOLATION LEVEL 在 SQL 层面设置
易错点:
- ❌ “RR 完全解决了幻读”——当前读场景需要手动加锁
- ❌ 混淆脏读/不可重复读/幻读的区别