677 字
3 分钟
InnoDB 快照读与当前读如何处理幻读
  1. 1MySQL 面试复习导读:知识地图与阅读路线
  2. 2MySQL 存储引擎怎么选:InnoDB、MyISAM 与 MEMORY
  3. 3MySQL 索引类型与 B+ 树:结构、分类和失效场景
  4. 4MySQL B+ 树查询全过程:从根节点到页目录
  5. 5InnoDB 聚簇索引与二级索引:什么是回表
  6. 6MySQL 覆盖索引:如何避免回表
  7. 7MySQL 联合索引的最左前缀匹配原则
  8. 8MySQL 索引下推:把过滤提前到存储引擎
  9. 9MySQL 事务异常读:脏读、不可重复读与幻读
  10. 10MySQL 四种事务隔离级别与选型取舍
  11. 11MySQL MVCC:Undo Log、版本链与 ReadView
  12. 12MySQL InnoDB 锁的分类:行锁、表锁与意向锁
  13. 13MySQL 乐观锁与悲观锁:冲突少时重试,冲突多时排队
  14. 14MySQL 发生死锁怎么办:检测、定位与处理
  15. 15MySQL 事务的 ACID 特性分别是什么
  16. 16InnoDB Redo Log 如何保证崩溃恢复
  17. 17InnoDB Undo Log 的回滚与 MVCC 作用
  18. 18MySQL Binlog 是什么,和 Redo Log 有什么区别
  19. 19一条 MySQL 查询从连接到返回结果经历什么
  20. 20如何用 EXPLAIN 读懂 MySQL 执行计划
  21. 21MySQL 为什么需要 Redo Log 与 Binlog 两阶段提交
  22. 22MySQL 崩溃后如何恢复已提交事务
  23. 23InnoDB Buffer Pool 如何提升查询与写入性能
  24. 24联合索引应该如何设计
  25. 25InnoDB 快照读与当前读如何处理幻读本文
  26. 26联合索引范围条件之后的列还能使用吗
  27. 27MySQL 索引看起来失效了,如何判断优化器的选择
  28. 28MySQL 8.0 如何定位并处理 InnoDB 死锁
  29. 29MySQL 慢查询如何定位和优化
  30. 30MySQL 的 ORDER BY、GROUP BY 与 filesort
  31. 31MySQL 普通索引和唯一索引如何选择
  32. 32MySQL 主从复制的基本流程是什么
  33. 33MySQL 主从延迟和读写分离如何处理
  34. 34MySQL 深分页为什么慢,如何改写
  35. 35InnoDB 主键应该如何设计
  36. 36MySQL 字符集与排序规则有什么区别
  37. 37数据库范式与反范式如何取舍

以 MySQL 8.0、InnoDB 为例,先区分两类读取。普通 SELECT 通常是快照读:它按事务的 ReadView 从版本链读取可见版本。在 REPEATABLE READ(RR)中,同一事务的 consistent read 通常复用第一次一致性读建立的视图,因此即使另一个事务提交了符合条件的新行,原事务重复普通查询仍看到原快照。它解决的是快照视角的一致性,不是把其他事务的写入锁住。

当前读读取当前可用的最新版本,并对读取或修改范围加锁,典型语句包括 SELECT ... FOR UPDATE、SELECT ... FOR SHARE、UPDATE 和 DELETE。在 InnoDB RR 下,对索引范围执行锁定读时通常使用 Next-Key Lock(记录锁加间隙锁)保护扫描区间,阻止并发事务插入会落入该区间的新记录,从而防止当前读场景的幻读。若按唯一索引做唯一值等值查找,可能只需记录锁;具体锁范围受索引、谓词和执行计划影响。

-- 事务 A,RR
START TRANSACTION;
SELECT * FROM orders WHERE amount >= 100; -- 快照读
-- 事务 B 插入 amount=120 并提交
-- A 再次普通 SELECT,仍读取其快照
SELECT * FROM orders WHERE amount >= 100;
-- A 改为当前读,会读取最新版本并锁定相应范围
SELECT * FROM orders WHERE amount >= 100 FOR UPDATE;

如果 A 在 B 提交后执行当前读,它可能看到新行;因此“RR 永远不会发生幻读”过于粗糙,必须说清读取类型。若业务需要“检查某范围为空后再插入”等互斥语义,应在同一事务用合适索引的锁定读保护范围,或用唯一约束等数据库约束兜底。READ COMMITTED 下普通快照读通常每条语句建立新视图,且 gap locking 行为与 RR 不同;不可把 RR 的锁范围结论直接套到其他隔离级别。

追问#

快照读会阻止其他事务插入吗?#

不会。普通 consistent read 通过 MVCC 读版本,不为查询范围加锁;要阻止插入需使用锁定读并确认索引和隔离级别。

SELECT ... FOR UPDATE 为什么可能锁住范围外的“行”?#

锁的是索引扫描涉及的记录和间隙,范围访问可能使用 Next-Key Lock;无合适索引时扫描及锁定范围可能很大。

怎样让“账号不存在才创建”并发安全?#

优先建立唯一索引并处理重复键冲突;若业务逻辑确需范围互斥,可在正确索引和隔离级别下使用锁定读,但不要仅依赖先查后插。

InnoDB 快照读与当前读如何处理幻读
https://blog.xqcherry.top/posts/interview/mysql/mysql-snapshot-vs-current-read-phantom/
作者
xqcherry
发布于
2026-10-12
许可协议
CC BY-NC-SA 4.0