Skip to content

脏读、幻读、不可重复读区别 ​

一句话答案 ​

三个都是"一个事务读到了不该读的数据"。按严重程度从高到低排序:

  • 脏读:读到别人没提交的。
  • 不可重复读:两次读同一行结果变了,别人 update 提交了。
  • 幻读:两次按同一条件查询,行数变了,别人 insert/delete 提交了。

后两者读到的都是已提交数据,属于"读的时机"问题。脏读读到的是随时可能回滚的数据,危害最大。

  • 不可重复读和脏读的区别是:脏读是某一事务读取了另一个事务未提交的脏数据。而不可重复读则是读取了前一事务提交的数据。

  • 幻读和不可重复读都是读取了另一条已经提交的事务(这点就脏读不同)。所不同的是不可重复读查询的都是同一个数据项。幻读针对的是一批数据整体(比如数据的个数)。

不可重复读和幻读到底有什么区别呢? ​

  • 不可重复读是读取了其他事务更改的数据,针对update操作

解决:使用行级锁,锁定该行。事务A多次读取操作完成后才释放该锁,这个时候才允许其他事务更改刚才的数据。

  • 幻读是读取了其他事务新增的数据,针对insert和delete操作

解决:使用表级锁,锁定整张表。事务A多次读取数据总量之后才释放该锁,这个时候才允许其他事务新增数据。

一、三个现象逐个场景推演 ​

1、脏读(Dirty Read):读到了未提交的数据

时刻事务 A事务 B
t1开始事务,查余额 = 100
t2开始事务,UPDATE 余额 = 200(未提交)
t3再查余额 = 200(读到脏数据)
t4ROLLBACK,余额回到 100
t5基于 200 做业务决策—— 数据是错的

要点:A 读到的 200 是一个从未存在过的中间状态。B 一旦回滚,A 拿着幻觉数据继续跑,转账、扣减类业务直接资损。

2、不可重复读(Non-Repeatable Read):同一行两次读不一样

时刻事务 A事务 B
t1开始事务,查余额 = 100
t2UPDATE 余额 = 200 并 COMMIT
t3再查同一行,余额 = 200

要点:两次读同一行,值变了——针对 update,破坏的是"一个事务内多次读取应一致"的预期。

3、幻读(Phantom Read):同一条件两次查,行数变了

时刻事务 A事务 B
t1开始事务,SELECT COUNT(*) = 10
t2INSERT 一条新记录并 COMMIT
t3同条件再 COUNT(*) = 11(多出"幻影"行)

要点:两次读的是一批数据,多/少了行——针对 insert/delete,破坏的是"同一条件查询结果集应稳定"的预期。个别行更新并不改变行数,所以它和不可重复读关注点不同。

二、隔离级别对照矩阵 ​

隔离级别脏读不可重复读幻读说明
READ UNCOMMITTED 读未提交可能可能可能性能最高,几乎不用
READ COMMITTED 读已提交(Oracle/PG 默认)不可能可能可能只能读到已提交数据,语句级快照
REPEATABLE READ 可重复读(MySQL InnoDB 默认)不可能不可能不可能(个别场景除外)MVCC + 临键锁双管齐下
SERIALIZABLE 串行化不可能不可能不可能读加共享锁,完全串行,并发最差

记忆口诀:级别每升一级,依次消灭脏读 → 不可重复读 → 幻读;代价是并发度逐级下降。

三、MVCC 如何"顺手"消除前两个 ​

MVCC(多版本并发控制)不做全局加锁,而是给每行藏版本、给每个事务发快照,让读写互不阻塞:

  • 版本链:InnoDB 每行有两个隐藏列——DB_TRX_ID(最近修改它的事务 id)和 DB_ROLL_PTR(指向 undo log 里的旧版本)。一行数据的历次修改串成一条链;

  • ReadView(快照):事务发起快照读时记录当时"活跃(未提交)事务集合"。读某行时沿版本链回溯,找到对自己可见的第一个版本。未提交的修改对当前事务不可见,脏读天然被消除;

  • RC vs RR 的差别只在快照时机:RC 每条语句生成一个新 ReadView(所以能看见别人新提交的 update → 不可重复读)。RR 只在事务第一次读时生成并复用到事务结束(前后一致 → 可重复读);

  • 幻读的消除要靠两种手段:快照读(普通 SELECT)靠 RR 级别的固定 ReadView 看不见新插入的行。当前读(SELECT ... FOR UPDATE / UPDATE / DELETE)靠临键锁(Next-Key Lock = 记录锁 + 间隙锁)锁住区间,堵住 insert 的入口。所以原文"解决幻读要用表级锁"是简化说法——InnoDB 用更细粒度的临键锁达到了同样效果;

  • 遗留边界:RR 下先快照读再当前读、或本事务自己 update 之后再看,仍可能看见幻影行。严格场景要显式加锁或升到 SERIALIZABLE。

延伸阅读:数据库两大神器之锁(锁粒度与 MVCC 的关系)、数据库两大神器之索引、[Spring 事务面试考点](../../Spring/04-事务与升级进阶/Spring 事务面试考点.md)。

2026-10 扩充(Round1 查漏)。