当前位置: 首页 > news >正文

MySQL——MVCC

1.为什么需要MVCC

在并发场景下,读写操作会面临严重的冲突问题:

1.读操作如果遇到写操作,要么“读到未提交的脏数据”,要么“被写操作阻塞(等待锁释放)”;

2.写操作如果遇到读操作,要么“覆盖读操作需要的数据”,要么“被读操作阻塞”;

MVCC通过“多版本”解决了这个问题:写操作会生成新的数据版本,读操作读取旧的版本(不影响写),两者不干扰。

2.什么是MVCC

MySQL的MVCC(Multi-Version Concurrency Control,多版本并发控制)是InnoDB存储引擎实现高并发读写的核心操作。核心思想:为数据库中的每条记录维护多个版本,通过“版本链”和“可间性判断规则”,让不同实物在并发访问时,能够看到符合自己隔离级别的数据版本,从而避免读写冲突(读不阻塞写,写不阻塞读),同事保证事务隔离性。

3.MVCC的核心组成

MVCC的实现依赖三个关键组件:隐藏列(版本标识)Undo Log(版本存储)Read View(可见性判断)

3.1 隐藏列:记录的“版本身份证”

InnoDB为表中的每条记录添加了三个隐藏字段,用于记录标识的版本信息

  • DB_TRX_ID:记录最后一次修改该记录的事务ID(6字节)。每次事务对记录执行insert/update/delete时,都会将自己的事务ID写入该字段。
  • DB_ROLL_PTR:回滚指针(7字节)。指向该记录的“上个版本”在Undo Log中的位置(通过它可以串联所有的历史版本,形成“版本链”)。
  • DB_ROW_ID:记录的唯一标识(6字节)。如果表没有定义主键或唯一索引,InnoDB会用它作为默认聚簇索引(一般用不到,可忽略)。

3.2 Undo Log:版本的“历史记录馆”

Undo Log(回滚日志)是InnoDB用于存储“记录旧版本”的空间。当视为修改记录时,旧版本的数据不会被直接删除,而是被写入Undo Log,供后序“回滚”或“其他事务读取”使用。

与隐藏列相结合形成“版本链”,记录的“版本链”形成的过程如下:

  1. 初始插入一条数据时,DB_TRX_ID是插入事务的ID,DB_ROLL_PTR为null(无历史版本,新数据无历史版本)。
  2. 当事务A(事务ID=110)修改该记录时,InnoDB会先将旧版本数据写入Undo Log,然后更新记录的DB_TRX_ID=110,并将DB_ROLL_PTR指向Undo Log中的旧版本。
  3. 之后事务B(事务ID=220)再次修改该记录时,会将“事务A修改后的版本”写入Undo Log,更新DB_TRX_ID=220,DB_ROLL_PTR指向事务A版本再Undo Log的位置。
  4. 最终,通过DB_ROLL_PTR串联的Undo Log记录,形成了改记录的“版本链”(最新版本在表中,历史版本在Undo Log中)。

一条记录的版本链结构(简化):
当前记录(表中):

data:(name='HajiHang',age=21)|DB_TRX_ID=220|DB_ROLL_PTR——>Undo Log中的版本1

Undo Log:

Undo Log中的版本1(事务A修改后的版本):

data:(name='HajiHang',age=20)|DB_TRX_ID=110|DB_ROLL_PTR——>Undo Log中的版本0

Undo Log中的版本0(初始插入版本):

data:(name='HajiHang',age=19)|DB_TRX_ID=55|DB_ROLL_PTR——>null

3.3 Read View:版本的“可见性过滤器”

有了版本链后,事务如何判断“哪个版本的数据对自己可见”?这就需要Read View(读试图),它是一个“可见性判断规则集合”,用于确定当前事务能够看到版本链中的那个版本。

Read View包含4个核心变量(生成时确定):

  1. m_ids:生成Read View时,当前所有“活跃事务”(已启动但未提交)的事务ID集合(无序)
  2. min_trx_id:m_ids中的最小事务ID(当前活跃事务中最早启动的那个)
  3. max_trx_id:生成Read View时,“下一个将要分配的事务ID”(并非m_ids中的最大值,而是一个预分配的自增ID)
  4. creator_trx_id:当前生成Read View的事务自己的ID

4.可见性判断规则(核心)

设记录的版本对应的事务ID为trx_id,根据trx_id和Read View的变量对比:

  • 如果trx_id == creator_trx_id:该版本是当前事务自己修改的,可见(自己改的自己当然可以看到)
  • 如果trx_id < min_trx_id:该版本对应的事务在“当前Read View生成前”就已提交(因为它的ID比所有活跃事务的最小ID还小),可见。
  • 如果trx_id >= max_trx_id:该版本对应的事务在“当前Read View生成后”才启动(ID超过预分配的最大ID),不可见(还没提交,或刚启动)。
  • 如果min_trx_id <=trx_id <=max_trx_id:
    • 若trx_id在m_ids(活跃事务集合)中:说明该事务在Read View生成时还没提交,不可见;
    • 若trx_id不在m_ids中:说明该事务在Read View生成前已提交,可见;

5.MVCC与隔离级别的关系

MVCC的核心作用是实现隔离级别(ACID中的“I”隔离性)。InnoDB通过“Read View的生成时机”和“版本链”,在不同隔离级别下表现出不同的行为:

隔离级别MVCC行为(Read View生成时机)解决的问题
Read Uncommitted(读未提交)不使用MVCC(直接读取最新的版本)可能读到未提交的脏数据(脏读)
Read Committed(读已提交)每次执行select时,重新生成Read View避免脏读(只看到已提交的版本);但是可能出现“不可重复读”(两次查询Read View不同)
Repeatable Read(可重复读)仅在事务第一次select生成Read View,之后复用避免不可重复读(两次查询用同一个Read View,版本一致);但可能出现“幻读”(通过间隙锁解决)
Serializable(串行化)不依赖MVCC,直接通过加锁(读加共享锁,写加排它锁)实现完全串行化,无并发问题,性能低

6.补充:不同隔离级别涉及到的并发问题

不同隔离级别会产生不同的并发问题,核心问题包括脏读,不可重复读,幻读。

  • 脏读指的是一个事务读取到另一个为提交事务修改的数据。(事务A在修改name并未提交,事务B读取到了name,后事务A又进行修改并提交/或直接回滚,导入事务B读取到了一个临时,无效的数据)
  • 不可重复读指的是同一事务内,多次读取同一数据,结果因其他已提交事务的修改而不同。(事务A第一次读取name='HajiHang',事务B执行了修改操作将name改成了Hajimi,事务A再次读取name发现不是HajiHang了)
  • 幻读指的是同一事务内,多次执行相同的查询操作(通常是范围查询)时,结果集行数因其他一提交事务的插入/删除而变化(事务A查询score=90的人发现有5条数据,之后事务B插入一个90的数据,事务A再次查询score=90发现结果集变为6条)

http://www.lryc.cn/news/603287.html

相关文章:

  • Django自带的加密算法
  • 汇总10个高质量免费AI生成论文网站,支持GPT4.0和DeepSeek-R1
  • 云端文档管理新纪元:Paperless-ngx与cpolar打造的无边界文件生态
  • PHP性能优化与高并发处理:从基础到高级实践
  • 深入理解Java Map的entrySet()方法
  • VLA--Gemini Robotics On-Device: 将AI带到本地机器人设备上
  • 在WSL中配置VS Code C++开发环境完整教程
  • LeetCode 1616.分割两个字符串得到回文串
  • 【21】C# 窗体应用WinForm ——图片框PictureBox属性、方法、实例应用
  • 【MySQL学习|黑马笔记|Day2】SQL|DML、DGL、DCL,函数,约束
  • redis得到shell的几种方法
  • 搭建专属AI聊天网站:NextChat + 蓝耘MaaS平台完整部署指南
  • 《C++初阶之STL》【list容器:详解 + 实现】
  • 夯实家庭基石本质上是一场“缓慢的革命”
  • 【Redis实现基础的分布式锁及Lua脚本说明】
  • 使用 Canvas 替代 <video> 标签加载并渲染视频
  • 【深度学习】独热编码(One-Hot Encoding)
  • 怎么提升服务器的防攻击能力!
  • day064-kodbox接入对象存储与配置负载均衡
  • 「源力觉醒 创作者计划」 百度AI的战略“惊蛰”,一场重塑格局的“破壁行动”
  • JSON在java中的使用
  • 力扣热题100--------240.搜索二维矩阵
  • 半导体企业选用的跨网文件交换系统到底应该具备什么功能?
  • Spring Boot 请求限流实战:基于 IP 的高效防刷策略
  • Qt 并行计算框架与应用
  • 重塑浏览器!微软在Edge加入AI Agent,自动化搜索、预测、整合
  • [明道云]-基础教学2-工作表字段 vs 控件:选哪种?
  • nodejs 实现Excel数据导入数据库,以及数据库数据导出excel接口(核心使用了multer和node-xlsx库)
  • 架构实战——互联网架构模板(“用户层”和“业务层”技术)
  • 向量内积:揭示方向与相似性的数学密码