Sunday面试指南

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 的独立解析。

浏览公司面试真题 →
简历汪永久免费在线制作简历,模板直接套用、导出无水印,永久免费、下载免费,不需要付费解锁任何功能。去写简历