MVCC 快照读为什么读不到刚提交的数据:ReadView 的 4 条可见性规则

发布时间:2026/10/9 10:26:12

MVCC 快照读为什么读不到刚提交的数据:ReadView 的 4 条可见性规则 个人主页 我不会起名字322 欢迎各位大佬莅临其他栏目 技术栈学习笔记 其他栏目 力扣Hot100题目解析 其他栏目 Go项目学习笔记 其他栏目 redis 其他栏目 mysql 文章目录一、每一行都藏着一个版本链二、ReadView一次快照的名册三、4 条可见性规则四、RC 和 RR 的真正差别只有一句话五、6 个能跑出来的小实验六、RR 不等于没有幻读七、长事务为什么危险undo 不能清理小结先复现一个让人怀疑自己学错了的现象。在 MySQL 的 InnoDB 存储引擎里account表中有这样一行balance 100两个会话按顺序操作-- 会话 B先跑BEGIN;UPDATEaccountSETbalance200WHEREid1;COMMIT;-- B 已经提交了-- 会话 A在 B 提交前就 BEGIN 过BEGIN;SELECTbalanceFROMaccountWHEREid1;-- 100-- ... 这里 B 提交了 ...SELECTbalanceFROMaccountWHEREid1;-- 还是 100 ?!B 明明提交了A 却像没看见一样。这不是缓存、不是连接池、也不是主从延迟——这是MVCC多版本并发控制在按规则办事A 的第二次查询用的是事务开始时生成的快照而不是当前最新的数据。要真正理解它关键不是背RR 可重复读、RC 读已提交这两句话而是搞清三件事版本链怎么形成、ReadView 里存了什么、可见性怎么判断。一、每一行都藏着一个版本链InnoDB 的每行记录除了你的字段还有两个隐藏列隐藏列含义DB_TRX_ID最后一次修改这行的事务 id6 字节DB_ROLL_PTR回滚指针指向 undo log 里这行的上一个版本DB_ROW_ID没有主键时自动生成的隐藏主键本篇不涉及每次UPDATE并不是原地改掉而是写入一条 undo 记录保存旧值 → 修改当前行 → 把这一行的DB_TRX_ID改成自己的事务 id →DB_ROLL_PTR指向那条 undo。这些旧版本会一直躺在数据库的 undo 表空间里谁需要谁去顺着链取。我们假设 id1 这行的初始版本由事务 30 写入balance 100。事务 40 把它改成 300事务 50 又改成 500版本链长这样当前行: balance500 DB_TRX_ID50 ──┐ ↓ roll_ptr undo: balance300 DB_TRX_ID40 ──┐ ↓ undo: balance100 DB_TRX_ID30 ──→ NULL所以能不能读到某个值这个问题被转换成了从当前行出发顺着这条链往回找哪一版对我可见二、ReadView一次快照的名册快照读普通SELECT在需要时会生成一个 ReadView它其实就是当时活跃事务的一张快照名册四个字段字段含义m_ids生成 ReadView 时**还活着未提交**的事务 id 列表min_trx_idm_ids里的最小值max_trx_id下一个将要分配的事务 id注意不是m_ids的最大值creator_trx_id创建这个 ReadView 的事务自己的 id以开头那个场景为例A 先BEGIN拿到事务 id 40B 拿到 50 并改了数据、提交了。如果 A 在整个事务一开始就生成了 ReadView那么m_ids [40, 50]、min_trx_id 40、max_trx_id 51、creator_trx_id 40。三、4 条可见性规则拿到一行数据后按下面的顺序判断伪代码就是 InnoDB 的真实逻辑对版本链上的某一版记它的 DB_TRX_ID 为 trx 1) trx creator_trx_id → 可见这是我自己改的 2) trx min_trx_id → 可见改它的那个事务早就提交了 3) trx max_trx_id → 不可见它在我生成快照之后才开始 4) min_trx_id trx max_trx_id: trx 在 m_ids 里 → 不可见我生成快照时它还没提交 trx 不在 m_ids 里 → 可见我生成快照时它已提交 不可见时顺着 DB_ROLL_PTR 找到上一版重新从第 1 条开始判断 一直找到可见版本或者链走完说明这行对我不存在。回到开头的例子A 看到的当前行DB_TRX_ID 50。规则 4 命中——50 在m_ids里生成快照时 B 还没提交不可见顺着指针回到上一版DB_TRX_ID 3030 min_trx_id40规则 2 命中可见读到 100。B 提交与否对 A 的这个 ReadView 毫无影响。四、RC 和 RR 的真正差别只有一句话这两级事务隔离级别的实现差别不在于判断规则而在于生成 ReadView 的时机隔离级别ReadView 生成时机效果READ COMMITTED每次SELECT都重新生成别人一提交就能看见REPEATABLE READ事务里第一次SELECT时生成之后一直复用整个事务看到同一个快照这也解释了另一个常见疑问为什么在 RR 下事务里第一条SELECT之前别人提交的数据是能看见的——因为ReadView 那时候还没生成等你第一次查询时名册是按当时状态拍的。-- 想自己验证RR 只在第一次 SELECT 时拍快照按这个顺序敲SETSESSIONtransaction_isolationREPEATABLE-READ;BEGIN;SELECTbalanceFROMaccountWHEREid1;-- 这里才生成 ReadView-- 另一个会话 UPDATE COMMITSELECTbalanceFROMaccountWHEREid1;-- 仍是旧值COMMIT;五、6 个能跑出来的小实验#操作结果说明1RR 下 A 读、B 更新并提交、A 再读两次相同快照复用符合直觉预期2同上但隔离级别是 RC第二次看到新值每次 SELECT 重新拍快照3A 自己UPDATE后再SELECT能看到自己的修改规则 1trx creator_trx_id4A 读、B 更新不提交、A 再读仍是旧值B 在m_ids里且脏读被阻断5ASELECT ... FOR UPDATE看到 B 已提交的新值当前读不走 ReadView6A 快照读期间大量写入A 看不到任何新行幻读在这条路径上被抑制第 5 条是最容易踩的坑SELECT ... FOR UPDATE、UPDATE、DELETE都是当前读它们读的是最新已提交版本还会加锁。所以你会看到同一个事务里BEGIN;SELECTbalanceFROMaccountWHEREid1;-- 100快照读SELECTbalanceFROMaccountWHEREid1FORUPDATE;-- 500当前读同一事务里数值跳了顺便说一下UPDATE的半一致性读更新时如果发现最新版本被别的事务锁着会等锁等到了就读取最新版本再做判断所以UPDATE ... WHERE balance 100在 RR 下也可能改到你以为不存在的行。六、RR 不等于没有幻读很多人把RR 解决了幻读当成定理。准确说法是RR 下快照读不会幻读当前读仍可能幻读。-- 会话 ABEGIN;SELECTCOUNT(*)FROMt_orderWHEREuser_id10;-- 0快照里确实没有-- 会话 B 插入 (10, ...) 并提交SELECTCOUNT(*)FROMt_orderWHEREuser_id10;-- 仍然是 0快照读UPDATEt_orderSETstatus1WHEREuser_id10;-- 影响 1 行当前读看到了新行SELECTCOUNT(*)FROMt_orderWHEREuser_id10;-- 现在是 1自己的修改对自己可见同一个事务里COUNT从 0 变成 1这就是幻读。真正挡住插入的是间隙锁见另一篇不是 MVCC。七、长事务为什么危险undo 不能清理版本链是给还活着的 ReadView服务的。只要还有一个事务没提交InnoDB 就必须保留它可能需要的旧版本于是purge线程清不掉 undo。判断标准是history list lengthSHOWENGINEINNODBSTATUS\G-- 搜 History list lengthSELECTtrx_id,trx_started,TIMESTAMPDIFF(SECOND,trx_started,NOW())ASsecs,trx_rows_locked,trx_queryFROMinformation_schema.innodb_trxORDERBYtrx_started;当History list length持续上涨、undo 表空间不断变大、查询越来越慢时十有八九是某处挂着长事务常见来源事务里发了 MQ、调了 RPC、Transactional包住了整个批量任务、或者连接池里一个BEGIN后忘了提交。注意只读的长事务同样会拖住 purge因为它持有的 ReadView 决定了旧版本的下限。小结每行数据通过DB_TRX_IDDB_ROLL_PTR串成版本链UPDATE不改历史只追加新版本。ReadView 是活跃事务名册4 条规则决定某一版能不能被我看见看不见就顺着链往回退。RC 与 RR 的差别只在生成 ReadView 的时机每条 SELECT vs 事务首次 SELECT。快照读走 MVCC当前读FOR UPDATE/UPDATE/DELETE走最新版本 加锁两者在同一事务里数值可以不一致。长事务会把 undo 按住不放监控History list length比监控慢查询更早发现问题。理解到这一层为什么读不到刚提交的数据就不再是玄学而是一条能画出来的判断链。
延伸阅读

更多相关文章

2026/10/9 10:21:12

内存故障蓝屏代码全解析:WinDbg与MemTest86排查指南

1. 从一次"换内存翻车"说起:蓝屏代码到底在说什么很多人第一次认真研究蓝屏错误代码,都是被逼的。我印象特别深的一次,是帮朋友处理一台老台式机——原本只是想把两条8G内存升级成两条16G,结果开机进系统不到三分钟就蓝…

2026/10/9 10:21:12

圆柱电池自动线技术解析:自动物流、化成分容与智能制造系统集成

随着动力电池和储能电池行业快速发展,圆柱电池制造正从传统人工模式向智能制造模式升级。自动化生产线已经成为提高效率、降低成本以及提升产品一致性的重要手段。本文从工程技术角度分析圆柱自动线的组成架构及关键技术。一、什么是圆柱自动线圆柱自动线是指将生产…

2026/10/9 10:21:12

华为OD机试真题 新系统 2026-09-20 JavaGoC【简单URL 路径提取器】

目录 题目 思路 Code 题目 题目内容: 在企业安全运营工作中,安全分析人员需要从海量日志中识别异常访问模式,统计出频率较高的 URL 路径模式。 现有一批访问日志,请提取出现次数不少于 2 次的不同 URL 路径前缀,并统计其出现次数。 路径前缀说明:对于 URL /a/b/c…

2026/10/9 13:42:02

Oracle补丁包p24006111安装指南:版本解读、opatch apply与避坑实践

简介:本资源为Oracle数据库11.2.0.4.161018版本的季度补丁包,补丁编号24006111,适用于64位Linux环境,面向需要维护企业级数据库的DBA与运维人员。该补丁属于Oracle定期发布的累积性更新,用于修复已知漏洞、增强安全性并…

2026/10/9 13:42:02

Claude Code 入门指南:从零开始掌握 AI 编程助手与 TaoToken 配置

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/9 13:42:02

手写汉字识别系统实战:从CNN网络设计到ONNX部署全流程

简介:面向Python与计算机视觉学习者的一套手写汉字识别系统,针对中文汉字笔画复杂、类别多且相似字易混淆的难题,给出了从数据预处理、模型搭建到训练测试与推理识别的完整方案。压缩包共包含56个文件,其中12个Python脚本负责数据…

2026/10/9 13:42:02

MATLAB双目标定实战:从参数调优到避坑指南

简介:这份资源面向计算机视觉入门者与需要完成课程实验的学生,围绕MATLAB工具箱展开双目标定的完整实践,帮助解决相机内外参数求解、几何失真校正与三维重建前的标定问题。压缩包共182个文件,约15.71MB,以128张jpg标定…

2026/10/9 13:37:01

PHP小程序自助打印系统:部署、支付回调与避坑实战

简介:这份2023全新UI自助打印系统云打印小程序源码,整合微信小程序端与PHP后端,面向需要快速搭建云打印服务的开发者、课程学员及技术爱好者。它覆盖UI设计、自助图文打印、云打印、小程序开发及后端接口等关键环节,适合毕设改版、…

2026/10/8 10:03:18

Jev+Agent接管浏览器:browser-use实战与jev-ultrafast性能优化

1. 从“Jev”说起:为什么我要把Agent接进浏览器“Jev”这个词最近在圈子里出现的频率越来越高,很多人第一次听到会以为是某个新模型的名字,其实它更像是一种思路——把Jev模型的能力当作底座,通过Agent的方式去接管浏览器&#xf…

2026/10/8 10:03:20

多智能体集群实战:DeepAgents编排、MCP与A2A协议及Skills体系

1. 从"单兵作战"到"集群协同":多智能体编排到底在解决什么问题如果你最近在折腾 Agent 相关的东西,大概率会有一种感觉:单个 Agent 能做的事情,其实很快就摸到天花板了。你给它一个提示词,挂几个工…

2026/10/8 6:05:44

无源低通滤波器设计实战:从RC到LC,手把手教你避开那些坑

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/9 0:04:27

毕业论文初稿完成后首次进行AIGC疑似度自查的摸底与分流策略

毕业论文初稿完成后首次进行AIGC疑似度自查的摸底与分流策略当数万字的学位论文初稿经历开题、实验、问卷与多轮文献梳理最终成形时,绝大多数研究生都会面临一道全新的形式审查关卡:AIGC 疑似度排查。在高校毕业审核流程中,盲审前的文本检测通…

2026/10/9 0:04:27

食堂节能改造源头工厂,商用厨房设备焕新方案广受好评

商用厨房作为餐饮经营、单位供餐的核心后勤阵地,其设备配置、动线规划与运维体系直接决定后厨作业效率、运营成本与合规性。从基础的灶具、制冷存储设备,到油烟净化、水处理等配套系统,每一个环节的合理性都与食品安全、能耗管控、消防安全挂…

还想了解更多?直接咨询顾问

免费诊断 + 免费方案 + 透明报价。

全国咨询热线400-8866-253
免费获取方案
☎咨询二维码 ☎ ↑