[面试题] 什么是脏读、不可重复读、幻读?
📖 版块 A:知识讲解版 (温故知新)
这三个概念是数据库事务并发执行时可能出现的“读一致性”问题,通常通过设置不同的事务隔离级别(Isolation Level)来解决。
-
脏读 (Dirty Read):
- 定义:一个事务读到了另一个事务“尚未提交”的数据。
- 场景:事务A修改了数据但未提交,事务B读取了该数据。如果事务A随后回滚,事务B读到的就是并不存在的“脏数据”。
-
不可重复读 (Non-repeatable Read):
- 定义:在同一个事务内,多次读取同一行数据,结果不一致。
- 场景:事务A读取了一行数据,此时事务B对该行进行了修改(Update)并提交。事务A再次读取,发现两次结果不一样。重点在于 Update 或 Delete。
-
幻读 (Phantom Read):
- 定义:在同一个事务内,多次按相同条件检索数据,发现结果集的“行数”发生了变化。
- 场景:事务A查询符合条件的数据,事务B插入(Insert)或删除了符合该条件的数据并提交。事务A再次查询,发现多出或少了几行,就像产生了幻觉。重点在于 Insert。
事务隔离级别与现象对照表:
🎤 版块 B:面试实战版 (高手逐字稿)
Q:什么是脏读、不可重复读、幻读?它们之间有什么区别?
🧠 破局思路:这道题表面考定义,实则考查对“隔离性”和“并发一致性”的深度理解。区分度在于能否清晰区分“不可重复读”与“幻读”的细微差别(行变更 vs 行数变更),以及是否了解主流数据库(如 MySQL InnoDB)是如何在实际应用中解决这些问题的。
💬 高手逐字稿:
关于这三个概念,它们本质上都是在多个事务并发执行时,由于隔离性不足导致的数据读取不一致问题。
首先是脏读。简单来说,就是事务 A 读取了事务 B 还没提交的数据。因为事务 B 随时可能回滚,所以事务 A 读到的可能是一个根本不存在的中间状态。这在生产中是绝对不允许的,通常我们至少要开启“读已提交(RC)”级别来规避。
其次是不可重复读。它的特征是在同一个事务里,前后两次读取“同一行”数据,结果却变了。这通常是因为在两次读取之间,另一个事务对这行数据做了 Update 操作并提交了。
最后是幻读。很多人会把幻读和不可重复读搞混。它们的区别在于:不可重复读侧重于数据的“修改”,而幻读侧重于数据的“增减”。比如我事务 A 按照一个范围查询出了 10 条记录,此时事务 B 插入了一条新数据并提交,我事务 A 再次查询发现变成了 11 条。这种“莫名其妙多出来一行”的感觉就是幻读。
这里我深入拆解一下它们的应对机制: 其实隔离级别的提升就是为了解决这些问题。比如 MySQL 默认的隔离级别是 Repeatable Read(可重复读),在这个级别下,它通过 MVCC(多版本并发控制) 机制,让事务在整个过程中读取的都是快照版本,从而彻底解决了脏读和不可重复读。
这时候可能会有一个容易被忽略的细节: 大家常说 RR 隔离级别不能完全解决幻读,但在 MySQL 的 InnoDB 引擎里,其实已经处理得很好了。InnoDB 在“快照读”(普通 Select)下通过 MVCC 解决幻读;在“当前读”(比如 Select for update)下,它会使用 Next-Key Lock(记录锁+间隙锁),直接锁住记录之间的间隙,防止其他事务插入新数据。
所以,在实际开发中,我们绝大多数场景直接使用 MySQL 默认的 RR 级别就能获得很强的一致性保障,只有在极少数对并发吞吐要求极高、且对数据一致性不敏感的场景下,才会降级到 RC 级别。