讲师中心 微信公众号
AI工具推荐 视频效率加速

为什么MySQL在RR级别下依然可能发生幻读现象

千涛大大_8992

千涛大大_8992

发布时间:2026-10-26 09:25:21

|

667人浏览过

|

来源于php中文网

原创

MySQL在RR级别下仍可能发生幻读,根本原因是RR仅通过MVCC保证快照读一致性,而当前读会暴露新插入行;混用快照读与当前读、Next-Key Lock未生效或执行计划变化均会导致语义幻读。

为什么mysql在rr级别下依然可能发生幻读现象

MySQL 在 RR 隔离级别下依然可能发生幻读,根本原因不是“InnoDB 没做好”,而是 RR 本身不承诺消灭所有幻读场景——它只在快照读(普通 SELECT)中靠 MVCC 隐蔽了幻影行;一旦混入当前读(如 UPDATE、SELECT ... FOR UPDATE),幻读立刻暴露。

快照读和当前读混用必然导致结果不一致

这是生产中最常翻车的点:同一个事务里,先执行一次普通 SELECT(快照读),再执行 UPDATE ... WHERE x > 10(当前读),两次看到的数据集合可能不同。

  • 第一次 SELECT * FROM t WHERE id > 10 返回 5 行 → 基于事务启动时生成的 ReadView,看不到其他事务新插入的行
  • 另一事务插入 id = 15 并提交
  • 本事务执行 UPDATE t SET status = 'done' WHERE id > 10 → 当前读穿透 MVCC,读到最新数据,实际更新 6 行
  • 再执行 SELECT * FROM t WHERE id > 10 → 仍返回 5 行(复用旧 ReadView)

业务逻辑若基于第一次查询结果做判断(比如“只有 5 条待处理,可以发 5 条通知”),但实际更新了 6 条,就构成语义层面的幻读——不是数据库报错,而是应用逻辑被悄悄破坏。

Next-Key Lock 只在特定当前读中生效

Next-Key Lock 是 InnoDB 防幻读的核心机制,但它有严格触发条件,不是“只要 RR 就自动启用”。

MySQL
MySQL

编写正确的MySQL查询,避免字符集、索引和锁方面的常见陷阱。

下载
  • 必须是当前读语句:SELECT ... FOR UPDATE、UPDATE、DELETE,普通 SELECT 不触发
  • WHERE 条件必须能走索引,且最好是范围查询(如 id BETWEEN 10 AND 20);等值查询(id = 15)只加记录锁,不锁间隙
  • 若字段无索引(如 name = 'Alice'),InnoDB 退化为全表扫描,Next-Key Lock 失效,仅加行锁或意向锁
  • 非唯一二级索引上等值查询(如 INDEX(b),b=10 存在多行),InnoDB 会向右扫描直到第一个不满足的值,锁住更大范围(如 (10, 15]),但这不是开发者能直观预期的

间隙锁的加锁范围取决于 B+ 树遍历路径

Next-Key Lock 不是静态锁定某几行,而是动态决定锁哪些 (gap_start, record] 区间,完全依赖索引结构和查询执行计划。

  • 表中主键 id 当前值为 10、20、30,则 SELECT * FROM t WHERE id > 20 FOR UPDATE 会锁 (20, 30] 和 (30, +∞)
  • 但 SELECT * FROM t WHERE id = 25 FOR UPDATE(无对应记录)只锁间隙 (20, 30),不锁任何记录
  • 如果查询条件无法命中索引(例如隐式类型转换:WHERE id = '25' 而 id 是 INT),索引失效,间隙锁直接消失

这意味着,你写的 SQL 看似一样,只要执行计划稍有变化(如统计信息过期、索引被删、参数类型不匹配),加锁行为就可能完全不同,幻读风险随之浮现。

真正可控的防幻读手段只有显式加锁

依赖 RR 默认行为来防幻读,等于把一致性交给运气。要业务级可靠,必须主动控制读取模式:

  • 所有需要强一致性的范围判断,统一改用 SELECT ... FOR UPDATE 或 SELECT ... LOCK IN SHARE MODE,让 MVCC 让位于锁机制
  • 避免在单个事务内混用普通 SELECT 和当前读——要么全程快照读(接受其“看不见新数据”的局限),要么全程当前读(用锁兜底)
  • 若必须“先查后更”,建议事务开始后立即执行一次带锁的当前读(如 SELECT COUNT(*) FROM t WHERE cond FOR UPDATE),提前建立锁范围,后续同条件操作就不会跳出该视图

最易被忽略的一点:即使你写了 FOR UPDATE,如果 MySQL 执行计划没走索引,或者你用的是 UNIQUE KEY 等值查询,间隙锁依然不生效——得看 EXPLAIN 输出的 key 和 type 字段,而不是只信 SQL 表面写法。

热门AI工具

更多
DeepSeek

DeepSeek是一款面向对话、写作、编程和推理场景的AI大模型工具。

豆包大模型

豆包大模型是一款由字节跳动推出的企业级大语言模型服务平台。

WorkBuddy

一款AI办公效率工具,主要用于腾讯云推出的AI原生桌面智能体工作台,适合需要提升相关任务效率的用户。

PixTV
PixTV Hot

PixTV是一款面向AIGC内容创作的AI视频生成工具。

讯飞智作

讯飞智作是一款AI视频创作工具,AI文本配音工具,数字人课程、营销视频制作。

二狗PPT
二狗PPT Hot

一款AI演示文稿工具,主要用于专为中式职场打造的AI PPT生成工具,适合需要提升相关任务效率的用户。

UpDream
UpDream Hot

一款AI视频创作工具,主要用于哔哩哔哩推出的自研AI视频创作工具,适合需要提升相关任务效率的用户。

切问学术

切问学术是一款AI论文写作工具,复旦大学NLP团队推出的AI学术智能体。

墨刀AI
墨刀AI Hot

一款AI图像与设计工具,主要用于产品经理的专属智能体,适合需要提升相关任务效率的用户。

相关专题

更多
数据分析工具有哪些
数据分析工具有哪些

数据分析工具有Excel、SQL、Python、R、Tableau、Power BI、SAS、SPSS和MATLAB等。详细介绍:1、Excel,具有强大的计算和数据处理功能;2、SQL,可以进行数据查询、过滤、排序、聚合等操作;3、Python,拥有丰富的数据分析库;4、R,拥有丰富的统计分析库和图形库;5、Tableau,提供了直观易用的用户界面等等。

4543

2023.10.12

SQL中distinct的用法
SQL中distinct的用法

SQL中distinct的语法是“SELECT DISTINCT column1, column2,...,FROM table_name;”。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

951

2023.10.27

SQL中months_between使用方法
SQL中months_between使用方法

在SQL中,MONTHS_BETWEEN 是一个常见的函数,用于计算两个日期之间的月份差。想了解更多SQL的相关内容,可以阅读本专题下面的文章。

1189

2024.02.23

SQL出现5120错误解决方法
SQL出现5120错误解决方法

SQL Server错误5120是由于没有足够的权限来访问或操作指定的数据库或文件引起的。想了解更多sql错误的相关内容,可以阅读本专题下面的文章。

6501

2024.03.06

sql procedure语法错误解决方法
sql procedure语法错误解决方法

sql procedure语法错误解决办法:1、仔细检查错误消息;2、检查语法规则;3、检查括号和引号;4、检查变量和参数;5、检查关键字和函数;6、逐步调试;7、参考文档和示例。想了解更多语法错误的相关内容,可以阅读本专题下面的文章。

3283

2024.03.06

oracle数据库运行sql方法
oracle数据库运行sql方法

运行sql步骤包括:打开sql plus工具并连接到数据库。在提示符下输入sql语句。按enter键运行该语句。查看结果,错误消息或退出sql plus。想了解更多oracle数据库的相关内容,可以阅读本专题下面的文章。

6460

2024.04.07

sql中where的含义
sql中where的含义

sql中where子句用于从表中过滤数据,它基于指定条件选择特定的行。想了解更多where的相关内容,可以阅读本专题下面的文章。

8861

2024.04.29

sql中删除表的语句是什么
sql中删除表的语句是什么

sql中用于删除表的语句是drop table。语法为drop table table_name;该语句将永久删除指定表的表和数据。想了解更多sql的相关内容,可以阅读本专题下面的文章。

1210

2024.04.29

Gradle插件开发入门教程
Gradle插件开发入门教程

本专题介绍Gradle插件开发的基本流程,涵盖插件类编写、自定义任务注册、扩展参数设计和插件应用方法,帮助你理解插件如何组织构建逻辑,减少多个项目之间的重复配置。

60

2026.10.22

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
PostgreSQL vs MySQL
PostgreSQL vs MySQL

共1课时 | 191人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn