MySQL 事务的四种隔离级别是什么?脏读、不可重复读和幻读有什么区别?
下面是一段教学用的模拟面试。
🧑💻 面试官:MySQL 有哪几种事务隔离级别?
🙋♂️ 我:读未提交、读已提交、可重复读和串行化。级别越高,数据越安全。
🧑💻 面试官:那把所有接口都设成串行化,是不是就最好?
🙋♂️ 我:也不一定。并发时可能增加等待。
🧑💻 面试官:换成 InnoDB 默认的可重复读。事务里先查一遍,再执行 UPDATE,为什么更新到的数据可能和刚才看到的不一样?
这道题要分清两件事:「允许发生什么并发现象」,以及「当前语句到底怎样读取数据」。背出四个名字,还没有答完。
面试速答(60 秒版)
事务隔离级别规定的是,多个事务同时读写时,一个事务可以看到其他事务的哪些变化。
读未提交可能读到别人还没提交的数据;读已提交只读取已提交的数据,但同一事务里,两次查询可能看到不同结果。可重复读进一步保证重复读取的稳定性;串行化则要求并发事务的效果能够按某个串行顺序解释。
脏读指读到未提交的修改。不可重复读通常讨论同一条记录的值变了。幻读讨论按照同一条件查询时,符合条件的记录集合变了,例如多出一条记录。
不过,解释 MySQL 时还要补上引擎和读取方式。在 InnoDB 的可重复读下,普通 SELECT 使用一致性快照;锁定读和 UPDATE 则按较新的数据状态加锁处理。因此不能把“可重复读”理解成事务里的所有语句永远看到同一份数据。
选型时,要同时考虑读取一致性、锁等待和事务长度。提高隔离级别不能代替唯一约束、条件更新以及正确的事务边界。

知识点详解:先看清读的是什么,再讨论隔离级别
用同一个余额,理解脏读与不可重复读
假设账户余额是 100,事务 A 要把它改成 80,事务 B 同时查看余额。
如果 A 还没提交,B 就读到 80,那么 B 读到的是尚未确定的结果。A 随后回滚,余额仍然是 100,B 刚才的判断却已经建立在 80 上。这就是脏读。
如果 B 第一次读到 100,随后 A 修改并提交,B 在同一事务中第二次读到 80,那么两次读到的都是合法的已提交数据,只是同一行的内容变了。这就是不可重复读。
区别不在于“读错了多少”,而在于被读到的修改有没有提交。

幻读关心的是符合条件的记录集合
再假设 B 查询“余额大于 50 的账户”。第一次有两条记录。A 新增一条满足条件的账户并提交,B 再按同一条件查询,结果变成三条。
B 关心的不是某一条账户余额从 100 变成 80,而是这个查询条件对应的集合发生了变化。
新增、删除,甚至修改字段使记录进入或离开查询范围,都可能影响集合。讲解时要把查询条件和前后结果写出来,不能只说“出现了一条幻影”。
四个级别不是四套完全不同的数据库
可以先记住 SQL 隔离级别对这些常见读现象的基本约束:
| 隔离级别 | 脏读 | 不可重复读 | 幻读 |
|---|---|---|---|
| 读未提交 | 可能 | 可能 | 可能 |
| 读已提交 | 不允许 | 可能 | 可能 |
| 可重复读 | 不允许 | 不允许 | 标准层面仍可能 |
| 串行化 | 不允许 | 不允许 | 不允许 |
这张表是理解级别的入口,不是 InnoDB 每一种语句行为的完整说明。
例如 InnoDB 的可重复读,普通 SELECT 在同一事务中通常沿用第一次一致性读建立的快照。别人后来插入并提交的新记录,不会因此出现在这份快照里。需要阻止其他事务向某个扫描范围插入时,则要看锁定读和范围锁的实际行为。索引条件也会影响锁住的范围。
所以,“标准可重复读允许幻读”和“InnoDB 在具体读取场景中避免了某些幻读”,并不矛盾。MySQL 8.4 官方说明分别解释了快照与加锁行为。
为什么刚查过的结果,不一定就是 UPDATE 使用的结果?
普通 SELECT 是在读一份一致性快照。UPDATE 不会拿这张旧快照直接修改历史版本,而是处理当前可更新的记录,并按规则加锁。
因此,在一个事务里混用普通查询和写操作时,需要分别分析。不能先查到“有库存”,就认为下一句扣库存一定成功。
库存扣减应把判断放进更新本身,例如“库存足够才扣减”,并检查影响行数;必要时还要配合锁定读。隔离级别只是其中一个条件,不负责替应用补上业务规则。

可以怎样用两个连接验证?
先在测试库建立账户记录,确认使用 InnoDB。连接 B 设置读已提交,再开始事务并查询余额。连接 A 修改这条记录并提交。B 在自己的事务结束前重新查询,可以观察两次结果是否变化。
再把 B 改成可重复读,重新开始一轮实验。让 B 的第一次普通 SELECT 先建立快照,再让 A 修改并提交。B 第二次普通查询通常仍看到原来的值。
注意,每一轮都要结束上一轮事务;隔离级别应在新事务开始前设置。演示快照读时,不要中途加上 FOR UPDATE。否则测试条件已经变了。
这是一套可复现的实验步骤,不是本文声称已经在本机跑出的结果。
面试官继续追问
读已提交一定比可重复读快吗?
不能直接下结论。它们的锁行为不同,可能影响冲突,但真实延迟还取决于索引、事务长度、查询量和写热点。用同一批请求比较锁等待、死锁、吞吐和一致性结果,才知道改级别是否值得。
串行化就是所有事务排队,一个接一个运行吗?
不等于实现上只能串行执行。它要求结果等价于某种串行顺序。数据库可以通过锁等机制执行并发事务,只是冲突时需要等待或处理失败。
保证可重复读,就不会重复插入订单了吗?
不会。两个事务仍可能同时尝试插入同一个业务标识。应该用唯一约束守住数据库边界,再让应用正确处理冲突。不要让隔离级别承担它没有承诺的功能。
面试速记卡
- 脏读:读到了其他事务尚未提交的修改。
- 不可重复读:同一事务重复读取,同一记录的值发生变化。
- 幻读:同一条件对应的记录集合发生变化。
- InnoDB 可重复读:普通快照读和锁定读、写操作要分开分析。
- 选型:同时看一致性要求与冲突成本,不能替代业务约束。
公司面试真题
真题根据求职者公开面经整理,题意经过概括,非逐字原话或公司官方题库;本文为 Sunday 的独立解析。
京东 · 数据开发 / 后端 · 校招
MySQL 的事务隔离级别有哪些?(题意整理)
京东数据开发工程师后端一面 ↗
原帖发布于 2025-08-31(秋招记录)