mysql幻读是怎么出现的_mysql并发问题分析

发布时间 - 2026-02-02 00:00:00    点击率:
幻读只在“当前读”下真实发生;RR隔离级别下普通SELECT是快照读,不产生幻读,而SELECT...FOR UPDATE等当前读语句因加锁机制缺陷(如无索引时仅行锁、不锁间隙)可能导致幻读。

幻读只在“当前读”下真实发生

很多人误以

为可重复读(RR)隔离级别下普通 SELECT 也会幻读,其实不会——RR 下的普通查询是快照读,读的是事务启动时的 MVCC 快照,新插入的行根本不可见。真正出现幻读的,一定是用了 SELECT ... FOR UPDATESELECT ... LOCK IN SHARE MODEUPDATE/DELETE 这类“当前读”语句。

典型现象:事务 A 执行 SELECT * FROM orders WHERE status = 'pending' FOR UPDATE 得到 5 行;事务 B 插入一条 status = 'pending' 的新订单并提交;事务 A 再次执行相同语句,突然返回 6 行——多出来的那条就是“幻行”。

为什么 RR 隔离级别仍挡不住幻读

关键在于 InnoDB 的加锁机制:RR 级别下,WHERE 条件无索引或索引不生效时,InnoDB 只能走全表扫描,此时仅对**实际命中的记录**加行锁(Record Lock),而对未命中但落在查询范围内的“间隙”(Gap)不加锁——这就给其他事务留下了插入空间。

  • 如果 status 字段没建索引,WHERE status = 'pending' 会锁住所有扫描到的行,但间隙不锁 → 幻读可发生
  • 如果 status 有索引,且查询能走索引,InnoDB 会升级为 Next-Key Lock(行锁 + 间隙锁),覆盖等值查询的前后间隙 → 大概率阻止幻读
  • 但如果查询条件是 WHERE status > 'a' 这类范围查询,即使有索引,也可能只锁部分间隙,仍存在漏插风险

真正有效的解决方式不是调高隔离级别

SERIALIZABLE 能彻底消灭幻读,但代价是所有 SELECT 都隐式加锁,高并发下极易锁等待甚至死锁,线上基本不用。

更务实的做法是结合场景主动控制:

  • 对关键业务逻辑(如库存扣减、订单生成),在事务开头就用 SELECT ... FOR UPDATE 锁住整个范围,且确保该字段有合适索引
  • 插入前先做一次“存在性校验查询”,但必须搭配 FOR UPDATE,否则校验和插入之间仍有窗口
  • 用唯一约束(UNIQUE KEY)替代应用层判断,让数据库直接拦截重复插入(注意:这防的是重复,不防幻读本身)
  • 业务上接受“最终一致性”的,可改用乐观锁(如版本号字段 + WHERE version = ?)配合重试

最容易被忽略的坑:d=5 这种无索引条件

看这个经典例子:SELECT * FROM t WHERE d = 5 FOR UPDATE,而 d 字段没有索引。InnoDB 只会对实际满足 d = 5 的行(比如 id=5)加行锁,其余扫描过的行(id=0,10,15…)不加锁,间隙更不锁。这时别人就能在 id=1、id=2 等任意空隙插入 d = 5 的新行,下次当前读就看到幻行了。

这不是 MySQL 的 bug,而是设计取舍:MVCC 解决快照读一致性,锁机制解决当前读一致性,两者分工明确。想靠 RR 一招鲜解决所有并发问题,本身就是对隔离级别的误解。


# mysql  # 为什么  # for  # select  # delete  # 并发  # 数据库  # bug  # 加锁  # 的是  # 这类  # 死锁  # 只在  # 锁住  # 能走  # 也会  # 很多人  # 能在 


相关栏目: 【 网站优化151355 】 【 网络推广146373 】 【 网络技术251813 】 【 AI营销90571


相关推荐: html5audio标签播放结束怎么触发事件_onended回调方法【教程】  网站制作壁纸教程视频,电脑壁纸网站?  小视频制作网站有哪些,有什么看国内小视频的网站,求推荐?  如何快速上传建站程序避免常见错误?  Laravel如何处理JSON字段的查询和更新_Laravel JSON列操作与查询技巧  Laravel如何实现用户角色和权限系统_Laravel角色权限管理机制  DeepSeek是免费使用的吗 DeepSeek收费模式与Pro版本功能详解  黑客如何利用漏洞与弱口令入侵网站服务器?  Android仿QQ列表左滑删除操作  制作公司内部网站有哪些,内网如何建网站?  网站制作免费,什么网站能看正片电影?  php json中文编码为null的解决办法  Laravel如何正确地在控制器和模型之间分配逻辑_Laravel代码职责分离与架构建议  Laravel如何使用Socialite实现第三方登录?(微信/GitHub示例)  Laravel怎么在Blade中安全地输出原始HTML内容  linux写shell需要注意的问题(必看)  谷歌Google入口永久地址_Google搜索引擎官网首页永久入口  Laravel如何发送系统通知?(Notification渠道示例)  千问怎样用提示词获取健康建议_千问健康类提示词注意事项【指南】  javascript基于原型链的继承及call和apply函数用法分析  Laravel怎么实现验证码功能_Laravel集成验证码库防止机器人注册  VIVO手机上del键无效OnKeyListener不响应的原因及解决方法  如何使用 jQuery 正确渲染 Instagram 风格的标签列表  Laravel如何使用Laravel Vite编译前端_Laravel10以上版本前端静态资源管理【教程】  Gemini手机端怎么发图片_Gemini手机端发图方法【步骤】  Laravel如何实现全文搜索功能?(Scout和Algolia示例)  如何在阿里云域名上完成建站全流程?  Laravel如何实现数据导出到PDF_Laravel使用snappy生成网页快照PDF【方案】  Laravel如何使用模型观察者?(Observer代码示例)  如何在阿里云香港服务器快速搭建网站?  如何在腾讯云服务器快速搭建个人网站?  使用C语言编写圣诞表白程序  java ZXing生成二维码及条码实例分享  香港服务器选型指南:免备案配置与高效建站方案解析  广州网站制作公司哪家好一点,广州欧莱雅百库网络科技有限公司官网?  Laravel如何实现本地化和多语言支持?(i18n教程)  Laravel如何使用Passport实现OAuth2?(完整配置步骤)  Edge浏览器怎么启用睡眠标签页_节省电脑内存占用优化技巧  Laravel如何配置.env文件管理环境变量_Laravel环境变量使用与安全管理  Laravel Asset编译怎么配置_Laravel Vite前端构建工具使用  Python文件异常处理策略_健壮性说明【指导】  网站建设要注意的标准 促进网站用户好感度!  如何在万网开始建站?分步指南解析  公司门户网站制作公司有哪些,怎样使用wordpress制作一个企业网站?  ,在苏州找工作,上哪个网站比较好?  Laravel如何集成微信支付SDK_Laravel使用yansongda-pay实现扫码支付【实战】  ,交易猫的商品怎么发布到网站上去?  Laravel控制器是什么_Laravel MVC架构中Controller的作用与实践  laravel怎么配置和使用PHP-FPM来优化性能_laravel PHP-FPM配置与性能优化方法  如何正确选择百度移动适配建站域名?