MVCC、幻读、间隙锁与临键锁(三)

news/2025/10/16 7:05:30/文章来源:https://www.cnblogs.com/jelly12345/p/19144686

一、MVCC解决了什么问题?

MVCC 解决了数据库高并发场景下的两大核心问题:

  1. 读写阻塞:在传统的锁机制下,读操作可能会阻塞写操作,写操作也一定会阻塞读操作。当有大量读写操作并发时,数据库性能会急剧下降。

  2. 事务隔离的代价:为了实现高级别的事务隔离(如可重复读),需要对数据加锁,这严重影响了并发性能。

MVCC的核心理念是:通过创建数据快照,让读操作和写操作互不阻塞。读操作访问事务开始时的快照版本,写操作则创建新版本。 这使得在 REPEATABLE READ 隔离级别下,读操作无需加锁,极大地提升了数据库的并发处理能力。


二、MVCC的原理是什么?

MVCC的实现依赖于三个核心要素:

  1. 隐式字段:

    • DB_TRX_ID:一个6字节的字段,表示最后一个对本行数据做修改的事务ID。

    • DB_ROLL_PTR:一个7字节的字段,指向回滚段中的Undo Log记录,也就是指向该行数据的上一个历史版本。

    • DB_ROW_ID:一个6字节的隐藏自增ID,如果表没有主键,InnoDB会基于此生成聚簇索引。

  2. Undo Log:

    • 当事务修改数据时,会将数据的旧版本拷贝到Undo Log中。

    • 这个Undo Log通过DB_ROLL_PTR指针形成一个数据版本链。如上图所示,最新的数据V2指向旧版本V1。读请求根据规则遍历这个链,找到适合自己的数据版本。

  3. Read View:

    • 这是事务进行快照读操作时产生的读视图。在事务执行快照读的那一刻,会生成数据库系统当前的一个快照。

    • Read View主要用于做可见性判断,即决定当前事务能看到哪个版本的数据。

    • 它主要包含:

      • m_ids:生成Read View时,系统中活跃的(未提交的)事务ID列表。

      • min_trx_id:活跃事务列表中的最小事务ID。

      • max_trx_id:生成Read View时,系统应该分配给下一个事务的ID。

      • creator_trx_id:创建该Read View的事务ID。

可见性判断规则:
沿着数据版本链,从最新版本开始检查,如果数据行的DB_TRX_ID

  • 等于creator_trx_id? -> 可见。说明是本事务自己修改的。

  • 小于min_trx_id? -> 可见。说明该版本在本次Read View创建前已提交。

  • 大于等于max_trx_id? -> 不可见。说明该版本在本次Read View创建后才生成。

  • min_trx_idmax_trx_id之间,但不在m_ids中? -> 可见。说明该版本对应的事务已提交。

  • min_trx_idmax_trx_id之间,且在m_ids中? -> 不可见。说明该版本对应的事务仍活跃,未提交。

如果不可见,就顺着DB_ROLL_PTR指针找到上一个版本,重复上述判断,直到找到可见的数据版本。


三、MySQL幻读解决了吗?

这是一个非常容易混淆的问题。结论是:

  • 在MySQL的InnoDB引擎的 REPEATABLE READ 隔离级别下,通过 MVCC + Next-Key Lock 的机制,已经解决了幻读问题。

什么是幻读?
一个事务在重新执行同一个查询时,返回了更多的行或者发现了之前不存在的行(由于其他事务的插入或删除操作)。

如何解决的?

  1. 对于快照读:普通的 SELECT ... 语句使用MVCC。因为事务始终读取的是它开始时的快照,所以其他事务的插入/删除操作对该事务是不可见的,从而防止了幻读。

  2. 对于当前读:像 SELECT ... FOR UPDATE / SELECT ... LOCK IN SHARE MODE / UPDATE / DELETE 这类操作,它们读取的是数据的最新版本,并且需要加锁。这时,MVCC无法防止幻读。InnoDB通过引入 Next-Key Lock 来给扫描到的索引范围加锁,阻止其他事务在锁定范围内插入新数据,从而解决了当前读下的幻读问题。

所以,标准的MySQL InnoDB在 REPEATABLE READ 级别下,已经可以完全防止幻读。


四、间隙锁和临键锁解决了什么问题?原理是什么?

它们共同解决了 "当前读" 场景下的幻读问题。

1. 间隙锁

  • 解决的问题:防止在某个索引记录的间隙中插入新数据,从而解决幻读。

  • 锁定的目标:锁定一个索引记录之间的开区间。例如,表中存在id为1和5的记录,那么间隙锁可能锁定区间 (1, 5)

  • 原理:当一个事务执行 SELECT * FROM table WHERE id BETWEEN 1 AND 10 FOR UPDATE 时,InnoDB不仅会锁住id=1和10的记录(如果存在),还会锁住(1,10)这个区间内的所有"间隙"。这阻止了任何其他事务在(1,10)的范围内插入新的id值,比如插入id=3或id=7,从而防止了幻读。

2. 临键锁

  • 本质:临键锁是 记录锁 和 间隙锁 的结合。

  • 锁定的目标:它会锁定索引记录本身以及该记录之前的间隙。

    • 例如,如果数据库中有索引记录10, 11, 13。

    • 那么临键锁可能锁定的区间是:(-∞, 10](10, 11](11, 13](13, +∞]

  • 原理:当执行 SELECT * FROM table WHERE id > 10 FOR UPDATE 时,InnoDB会从找到的第一个大于10的记录(比如11)开始,对其加临键锁(锁住(10, 11]),然后继续向后加锁,直到最后一个记录,最后还会对最后一个记录之后的间隙(比如(13, +∞))加一个间隙锁。这样,任何想在锁定范围内插入新数据的操作都会被阻塞。

💎 总结

 
机制核心解决问题原理
MVCC 快照读的读写阻塞与不可重复读 通过Undo Log版本链和Read View实现多版本数据快照,读操作无需加锁。
间隙锁 当前读的幻读(防止插入) 锁定索引记录之间的空隙,阻止其他事务在范围内插入新数据。
临键锁 当前读的幻读(防止插入和修改) 记录锁 + 间隙锁,锁定记录本身及之前的间隙,是InnoDB默认的行锁算法。

它们协同工作,使得MySQL InnoDB在 REPEATABLE READ 隔离级别下,既保证了高并发性能(通过MVCC),又实现了严格的事务隔离,解决了脏读、不可重复读和幻读所有问题。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/937959.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

MVCC、幻读、间隙锁与临键锁

一、MVCC 解决了什么问题? 🌱 背景:并发读写冲突 当多个事务同时操作同一行时,最经典的冲突是:A 在读;B 在写;A 还没提交,B 改了数据;如何让 A 看到一致的结果?MVCC(Multi-Version Concurrency Control,多…

MVCC、幻读、间隙锁与临键锁(二)

1. MVCC 解决了什么问题? MVCC(多版本并发控制)是 MySQL InnoDB 存储引擎实现并发访问的核心机制,主要解决了读写冲突问题:在传统锁机制中,读操作需要加共享锁,写操作需要加排他锁,会导致 “读阻塞写、写阻塞读…

读AI赋能01超级能动性

读AI赋能01超级能动性1. 超级能动性 1.1. 通货膨胀已成为全球最令人担忧的问题 1.2. 科技行业仍难以摆脱广告业务放缓、投资者情绪转变以及用户参与模式变化带来的叠加影响1.2.1. 负面结果只是对科技行业在疫情期间出现…

生物聚酯塑料回收技术创新与商业应用

本文介绍了生物聚酯塑料的化学回收技术突破,包括EsterCycle低能耗甲醇解工艺和Glacier的AI视觉分拣系统,并通过商业试验验证了生物聚酯材料在零售场景中的应用效果,推动塑料循环价值链建设。更优塑料之路:进展与合…

189 轮转数组 - MKT

189 轮转数组 class Solution { public:// 通过1 time 0ms 100% space 30.mb 5% 自己 内存大void rotate1(vector<int>& nums, int k) {// 1 余数 2 是否大于边界// 10 6 16=6 12-10=2cout<<&quo…

SGD 到 AdamW 优化器的实践选型指南

在深度学习的模型训练过程中,优化器扮演着至关重要的角色。它就像一位经验丰富的向导,带领模型在复杂的参数空间中寻找最优解。从早期简单的随机梯度下降到如今广泛使用的 AdamW,优化器的发展历程充满了对效率与精度…

# ️ MySQL vs PostgreSQL架构深度对比分析报告

# ️ MySQL vs PostgreSQL架构深度对比分析报告Posted on 2025-10-16 02:32 吾以观复 阅读(1) 评论(0) 收藏 举报关联知识库:# ️ MySQL vs PostgreSQL架构深度对比分析报告️ MySQL vs PostgreSQL架构深度对比分…

# 韩国数据中心大火:647套系统因缺失双活集体宕机22小时

# 韩国数据中心大火:647套系统因缺失双活集体宕机22小时Posted on 2025-10-16 02:32 吾以观复 阅读(1) 评论(0) 收藏 举报关联知识库:# 韩国数据中心大火:647套系统因缺失双活集体宕机22小时韩国数据中心大火…

# TLP电池管理工具:Linux笔记本续航优化的终极指南

# TLP电池管理工具:Linux笔记本续航优化的终极指南Posted on 2025-10-16 02:32 吾以观复 阅读(0) 评论(0) 收藏 举报关联知识库:# TLP电池管理工具:Linux笔记本续航优化的终极指南TLP电池管理工具:Linux笔记…

LlamaIndex API Example

LlamaIndex API ExamplePosted on 2025-10-16 02:32 吾以观复 阅读(0) 评论(0) 收藏 举报关联知识库:LlamaIndex API ExampleReader and Query Engine documents = SimpleDirectoryReader(files).load_data() re…

AI中间件机遇与挑战:从Agent到组织级智能的技术演进

AI中间件机遇与挑战:从Agent到组织级智能的技术演进Posted on 2025-10-16 02:32 吾以观复 阅读(0) 评论(0) 收藏 举报关联知识库:AI中间件机遇与挑战:从Agent到组织级智能的技术演进️ AI中间件机遇与挑战:从…

# Redis日常使用与性能排查指南

# Redis日常使用与性能排查指南Posted on 2025-10-16 02:32 吾以观复 阅读(0) 评论(0) 收藏 举报关联知识库:# Redis日常使用与性能排查指南Redis日常使用与性能排查指南 草稿内容 常用命令:info指令 9大块 s…

金耀初讲座——高效演化神经结构搜索

金耀初讲座——高效演化神经结构搜索![assets/金耀初讲座——高效演化神经结构搜索/Untitled.png]] ![assets/金耀初讲座——高效演化神经结构搜索/Untitled 1.png]] ![assets/金耀初讲座——高效演化神经结构搜索/Unt…

二手车检查

二手车检查车源:二手车之家app和懂车帝app,因为上面车商具有营业资格,可初步筛选车商 询问时:漆面状态(哪些面补过漆) 换件情况 四门(大事故),四梁(前后横纵防撞梁),六柱(车身骨架),所有玻璃(批号显示…

图文并茂展示CSS li 排版大合集,总有一款是你刚好需要的

@目录🐱 A. 基础列表样式🌟 1. 默认样式📝 无序列表🔢 有序列表✨ 2. 自定义项目符号🚀 B. 高级布局与定位🖼️ 3. 使用图片作为项目符号🧹 4. 移除默认样式🧭 5. 水平导航栏💫 C. 创意与装饰效果�…

The lamentable decline of reading

https://www.ft.com/content/583de986-a295-4697-a2fe-3c6b13c99145 The lamentable decline of readingChildhood encouragement, libraries and government support can reverse the trendTHE EDITORIAL BOARDAdd to…

[FT.COM]The world should prepare for the looming quantum era

https://www.ft.com/content/96e14cb0-f49f-4632-b94f-2d1cdc625f8b The world should prepare for the looming quantum eraNew breakthroughs underscore the technology’s potential and perilsTHE EDITORIAL BOAR…

10.15 闲话

镜中的昆虫曹髦,字彦士,常称其为“高贵乡公”。甘露五年五月己丑日,在诛杀司马昭的过程中被成济刺死。 我认为三国杀对曹髦的刻画是非常成功的。【潜龙】属于前期劣势,后期爆发的技能。【清正】和【酒诗】都不算能…

函数的类型注释器

在看别人的代码的时候你是否会看到经常会有这种情况 def haha(aa:str) -> np.ndarray:pass这里面的:str还有->代表什么呢? 其实他们就是为了让我们的代码的函数更加容易理解,规范输入输出的类型,所以使用了函…

如何手动构建一个线性回归模型

import numpy as np from utils.features import prepare_for_training # 预处理 import torch as t# 现在开始构建线性回归 class LinearRegression():"""总结一下这个函数具体做了什么事情:1. 预处理…