MySql的MVCC实现机制

article/2025/9/15 12:05:01

MVCC实现机制

  • 快照读和当前读
  • MVCC

快照读和当前读

在了解MySql的MVCC实现之前,需要先了解什么是快照读和当前读,以便于后续讲解
快照读:就是单纯的 SELECT 语句,不包括下面这两类语句:

SELECT ... FOR UPDATE
SELECT ... LOCK IN SHARE MODE

在RC事务隔离级别下,快照读和当前读显示数据是一样的
在RR事务隔离级别下,快照读有可能读取到的不是最新数据

当前读:每次都获取最新数据,但是获取最新数据时会自动加锁,读的过程中不允许写入数据。

此时有人可能会问,什么时候是快照读,什么时候是当前读?

普通的SELECT语句一般查询都是快照读,直接读取快照中的数据,在事务创建时,只有第一次执行SELECT语句才会生成快照,并不是事务创建后立马生成快照,在InnoDB引擎中默认的RR事务级别下,第二次执行SELECT语句会直接读取第一次SELECT生成的快照,所以说快照读有可能读取到的不是最新数据。
在执行以下SQL语句时,会进行当前读

select … lock in share mode 、
select … for update、
update 、delete 、insert

我们假设一个场景:

当前DB已有id 5, 10, 15三条数据。
事务A查询id < 10的数据,可以查出一行记录id = 5
事务B插入id = 6的数据
事务A再查询id < 10的数据,可以查出一行记录id = 5,查不出id = 6的数据(读场景,解决了幻读)
事务A可以执行更新/删除操作,然后查询id < 10 的数据,会发现可以查询到5和6两条数据(更新和删除操作进行了当前读,快照中的数据发生了变更)

换句话说:MySQL innodb 在 RR 隔离下一样会出现幻读,next-key lock 和 MVCC 只解决了部分幻读的场景。

故而:在标准的RR下,并没有彻底解决幻读问题,但是在Mysql的innodb引擎中使用 Next-Key lock加锁,读数据期间不允许写操作,从而彻底解决了幻读问题

MVCC

了解了快照读和当前读以后,我们再继续看一下MVCC的具体实现机制
MVCC是Multi-Version Concurrency Control(多版本并发控制)的缩写,MVCC没有统一的实现标准,不同的存储引擎对MVCC的实现方式是不同的,典型的有乐观并发控制和悲观并发控制。InnoDB对MVCC的实现采用的是乐观并发控制。
《高性能MySQL》这个书中介绍InnoDB-MVCC实现方式:

InnoDB的MVCC,是通过在每行记录后保存两个隐藏的列来实现的(用户不可见)。一个列保存行创建的时间,一个列保存行过期(删除)的时间,这里所说的时间并不是传统意义上的时间,而是系统版本号

  • SELECT
    InnoDB会根据以下两个条件检查每行记录:
    (1)InnoDB只查找版本早于当前事务版本的数据行(行的系统版本号小于或者等于事务的系统版本号),这样可以确保事务读取到的行,要么是在事务开始之前已经存在的,要么是事务自身插入或者修改过的;
    (2)行的删除版本要么未定义,要么大于当前事务版本号。可以确保事务读取到的行,在事务开启之前未被删除。
  • INSERT
    InnoDB为新插入的每一行保存当前系统版本号作为行版本号。
  • DELETE
    InnoDB为删除的每一行保存当前系统版本号作为行删除标识。
  • UPDATE
    InnoDB将更新后的列作为新的行插入数据表,并保存当前系统版本号作为该行的行版本号,同时保存当前系统版本号到原来的行作为行删除标识。

读完后,我们假设场景:在RR隔离级别下我开启了一个事务(事务版本号:1),并且插入了一条id = 10的数据行,这条数据的行版本号应该是创建它的事务版本号1,此刻(上一条事务未提交)我新开启一个事务(事务版本号2),对全表进行SELECT,按照上面的逻辑当前事务可以查询到版本小于当前事务版本的数据行,那就是说可以查询到id = 10的数据。但是,按照RR隔离级别的约定,版本号为2的事务并不被允许读取到这行数据,这就产生了矛盾。说到这里,大家也都应该能体会到我说的问题所在了。

接下来我们看看MySql官方文档说法:明确指出InnoDB为每一行数据都添加了三个隐藏字段,而删除标记有没有开辟特有的字段并未显式的说明,只说了在“特殊位置”被标记删除。也就是说,InnoDB 的叶子段存储了数据页,除了用户定义的字段以外还有三个隐式的字段。简单的结构如下:
DB_ROW_ID:6-byte,隐藏的行 ID,用来生成默认聚簇索引。如果我们创建数据表的时候没有指定聚簇索引,这时 InnoDB 就会用这个隐藏 ID 来创建聚集索引。采用聚簇索引的方式可以提升数据的查找效率。
DB_TRX_ID:6-byte,操作这个数据的事务 ID,也就是最后一个对该数据进行插入或更新的事务 ID。
DB_ROLL_PTR:7-byte,回滚指针,也就是指向这个记录的 Undo Log 信息。
请添加图片描述
什么是回滚段?

回滚段是一个保存每条数据行之前版本日志的地方。回滚段中的撤销日志分为插入和更新撤销日志,插入撤销日志仅仅在事务回滚时需要,事务一提交就可以丢弃,更新撤销日志也用于一致性读取,但是只有在InnoDB没有分配快照的情况下,才可以丢弃这些快照,在一致性读取中可能需要更新撤销日志中的信息来构建数据库行的早期版本。

回滚段如何构造?

当一个事务更新一条记录时,会将更新后的记录作为新的一行插入,将旧的行构建为undo_log记录在回滚段中,并将新数据行的回滚字段DB_ROLL_PTR指向这个undo_log,当多个事务更新同一条事务时,undo_log会形成链式结构。

在这里插入图片描述
我们开始具体讨论InnoDB-MVCC是如何实现多版本控制的。多版本实际上就是不同的事务都有着自己可视的数据版本,不同的事务数据版本是不同的。InnoDB-MVCC通过快照读的方式构建事务自己的可视版本,简单来说就是在事务操作之前获取当前的数据快照,这个快照所“呈现”的数据就是我当前事务的可视版本。那么快照该如何构建呢?继续往下看。

READ_VIEW

read_view是MySQL底层实现的一个结构体,是和SQL语句绑定的,在每个SQL语句执行前申请或获取。可以将其理解为构造快照的前提或者依据,一个快照所呈现的数据是什么样子(版本)的基本依赖于read_view中所存储的数据。

READ_VIEW底层实现
在这里插入图片描述

read_view是MySQL底层使用C++代码实现的一个结构体,构建当前可视版本(快照)主要用到的变量有low_limit_id、up_limit_id、trx_ids以及creator_trx_id:

low_limit_id:表示创建read_view时,当前事务活跃读写链表中最大的事务ID
up_limit_id:表示创建read_view时,当前事务活跃读写链表中最小的事务ID
trx_ids:创建read_view时,活跃事务链表里所有的事务ID
creator_trx_id:当前read_view所属事务的事务版本号

什么是当前事务活跃读写链表呢?可以将其理解为一个事务池,事务池中所存储的是当前所有正在运行(已开启但未提交)的事务。MySQL将当前所有活跃的事务保存在information_schema.innodb_trx表中,如下图所示:

在这里插入图片描述
MVCC会根据read_view中所保存的信息来构建当前事务可视版本。

对于小于或者等于RC的隔离级别,事务开启后,每次执行SQL语句都会申请一个read_view,然后在执行完这个SQL语句后,调用read_view_close_for_mysql将read view从事务中删除。每次在执行SQL语句之前都会判断trx->read_view为空(理论下必为空),然后重新申请一个read_view(这就是为什么RC隔离级别下会产生不可重复读的原因)。

对于RR隔离级别,当申请一个read_view后,事务未提交不会删除,整个事务将不再申请新的read_view,保证事务中所使用的read_view都是同一个,从而实现可重复读的隔离级别。
MVCC-SELECT可见范围(总结)

了解了这么多,我们再回过头来总结一下MVCC的SELECT规则。因为除了上面所提到了部分内容,官方文档中也没有很详细的介绍MVCC的具体操作,我看了很多网上的总结,有人总结了三条,也有人总结了四条,但通过分析以后,本文总结六条供大家参考:

(1):DB_TRX_ID >= view->low_limit_id的记录不可见。DB_TRX_ID >= view->low_limit_id的记录必为当前事务开启之后开启的事务更新或插入的,所以不可见;

(2):DB_TRX_ID位于[view->up_limit_id,view->low_limit_id)区间时,如果存在于trx_ids集合中,则不可见。如果DB_TRX_ID存在于这个集合中,说明该记录的修改或创建者(事务)在当前事务开启时并未提交,所以不可见;

(3):DB_TRX_ID up_limit_id的记录可见。DB_TRX_ID up_limit_id,说明该记录的修改或创建者(事务)在当前事务开启之前已经提交,所以可见;

(4):DB_TRX_ID = creator_trx_id的记录可见。DB_TRX_ID = creator_trx_id说明该记录的修改或创建者(事务)是当前事务,所以可见;

(5):DB_TRX_ID != creator_trx_id的被标记删除记录可见。所有被删除且已提交的事务将被真正删除(删除但未提交只是标记删除),所以不会查询到,标记删除的记录除自身删除的以外,当前事务可见,DB_TRX_ID = creator_trx_id为自身删除所以不可见,其余皆可见;

(6):以上对于view不可见的记录,需要通过记录的DB_ROLL_PTR指针遍历回滚段中的undo_log构造当前view可见版本数据。不可见的记录只是说明该记录的当前版本不可见,但是它之前的某一版本是当前事务可见的,所以应当构建出该数据当前事务的可见版本。


http://chatgpt.dhexx.cn/article/XpvLwk6I.shtml

相关文章

MVCC机制略解

在mysql中&#xff0c;默认的隔离级别是可重复读。即在一个事物中读取到的数据总是一样的&#xff0c;即使其他事务把数据改了&#xff0c;那在这个事务中读取的数据还是第一次读取的数据。 mysql还可以设置为读已提交隔离级别。即一个事务中读取的数据&#xff0c;随着其他事务…

什么是MVCC,一文搞懂MySQL的MVCC机制

MVCC是什么 MVCC&#xff0c;即Multi-Version Concurrency Control &#xff08;多版本并发控制&#xff09;。它是一种并发控制的方法&#xff0c;一般在数据库管理系统中&#xff0c;实现对数据库的并发访问&#xff0c;在编程语言中实现事务内存。 数据库中同时存在多个版本…

对MVCC全面解析

简介 MVCC&#xff08;Multi-Version Concurrency Control&#xff09;即多版本并发控制。 MVCC的实现原理 我们在了解MVCC之前&#xff0c;首先先了解一下几个比较常见的锁。 读锁&#xff1a;也叫共享锁、S锁&#xff0c;若事务T对数据对象A加上S锁&#xff0c;则事务T可…

【MySQL】MVCC机制

什么是MVCC MVCC 英文全称&#xff1a;Multi-Version Concurrency Control&#xff0c;Mysql的事务隔离性就是主要靠MVCC机制来实现的。对一行数据的读和写默认是不会通过加锁互斥来保证隔离性的&#xff0c;这样避免了频繁的加锁互斥&#xff0c;而在串行化隔离级别为了保证较…

一文精通MVCC机制

MVCC(Multi-Version Concurrency Control)多版本并发控制机制 使用串行化隔离级别时&#xff0c;mysql会将所有的操作加锁互斥&#xff0c;来保证并发安全。这种方式必然降低并发性能。mysql在读已提交和可重复读隔离级别下&#xff0c;对一行数据的读和写两个操作默认是不会通…

数据库的MVCC机制

MVCC 1. 什么是MVCC MVCC &#xff08;Multiversion Concurrency Control&#xff09;&#xff0c;多版本并发控制。顾名思义&#xff0c;MVCC 是通过数据行的多个版 本管理来实现数据库的 并发控制 。这项技术使得在InnoDB的事务隔离级别下执行 一致性读 操作有了保 证。换言…

MySQL之MVCC机制

1. MVCC概念 MVCC&#xff0c;全称Multi-Version Concurrency Control&#xff0c;即多版本并发控制。MVCC是一种并发控制的方法&#xff0c;一般在数据库管理系统中&#xff0c;实现对数据库的并发访问&#xff0c;在编程语言中实现事务内存。 在Mysql的InnoDB引擎中就是指在…

【MySQL进阶-05】深入理解mvcc机制(详解)

MySql系列整体栏目 内容链接地址【一】深入理解mysql索引本质https://blog.csdn.net/zhenghuishengq/article/details/121027025【二】深入理解mysql索引优化以及explain关键字https://blog.csdn.net/zhenghuishengq/article/details/124552080【三】深入理解mysql的索引分类&a…

MVCC及实现原理

&#xff01;首先声明&#xff0c;MySQL 的测试环境是 5.7 前提概要 什么是 MVCC什么是当前读和快照读&#xff1f;当前读&#xff0c;快照读和 MVCC 的关系MVCC 实现原理 隐式字段undo日志Read View整体流程MVCC 相关问题 RR 是如何在 RC 级的基础上解决不可重复读的&#xf…

4gl程式debug常用技巧

1、带参数的D&#xff1a; ‘MISC’表示具体料号传入 2、指定行数设置断点 比如我要在程式axmt360中的211行开始D 进入Debug界面后按ctrlD 弹出界面 输入b 行数 点OK 出现上面表示已设置OK&#xff0c;然后点cancel或叉叉退出 最后点下面按扭&#xff0c;程式跑到210行时自…

【OpenGL】十五、OpenGL 绘制三角形 ( 绘制 GL_TRIANGLE_FAN 三角形扇 )

文章目录 一、绘制 GL_TRIANGLE_FAN 三角形1、绘制 3 个点的情况2、绘制 4 个点的情况3、绘制 5 个点的情况4、绘制 6 个点的情况 二、相关资源 一、绘制 GL_TRIANGLE_FAN 三角形 GL_TRIANGLE_FAN 的绘制规则是 , 以第 1 1 1 个点作为顶点 , 第 1 , 2 , 3 1,2,3 1,2,3 个点组…

Unity3D笔记十八 GL图像库

作者&#xff1a;PEPE 出处&#xff1a;http://pepe.cnblogs.com/ 1、绘制2D图像的时需要使用GL.LoadOrtho()方法来将图形映射到平面中。 2、所有绘制相关的内容都要写在OnPostRender()方法中。 3、有关GL图像库的脚本需要绑定到Hierarchy视图中Camera上&#xff0c;否则无法…

Mapbox GL插件之echartsLayer

Mapbox GL除了本身的api具有的功能以外&#xff0c;还能够集成各种开源的类库。 ECharts 是一个使用 JavaScript 实现的开源可视化库&#xff0c;涵盖各行业图表&#xff0c;百度公司开发的&#xff0c;同时其中也有一些地图的效果。 Mapbox GL的echarts插件&#xff0c;在gith…

【OpenGL】十八、OpenGL 绘制多边形 ( 绘制 GL_POLYGON 模式多边形 )

文章目录 一、绘制 GL_POLYGON 模式多边形二、多边形绘制顺序分析三、相关资源 一、绘制 GL_POLYGON 模式多边形 使用 glBegin(GL_POLYGON) 设置绘制多边形 , 不管有几个点 , 都按照指定的顺序连接起来 ; 注意 : 这些点组成的多边形必须是凸多边形 , 不能是凹多边形 ; 代码示例…

gl_FragCoord 的含义

gl_FragCoord 表示当前片元着色器处理的候选片元窗口相对坐标信息&#xff0c;是一个 vec4 类型的变量 (x, y, z, 1/w)&#xff0c; 其中 x, y 是当前片元的窗口坐标&#xff0c;OpenGL 默认以窗口左下角为原点&#xff0c; 在 着色器中通过布局限定符可以重新设定原点&#xf…

WebGL着色器内置变量gl_PointSize、gl_Position、gl_FragColor、gl_FragCoord、gl_PointCoord

WebGL着色器内置变量 WebGL中文教程网 本文是WebGL教程(电子书)的2.7节内容 着色器语言在GPU的着色器单元执行&#xff0c;javascript语言、C语言在CPU上执行&#xff0c;任何一种语言的语法规则&#xff0c;整体设计都和它执行的硬件有一定的关系&#xff0c;GPU和CPU执行程…

Unity画线之GL

上一篇中&#xff0c;SetPixel的方法&#xff0c;卡顿严重&#xff0c;暂未解决&#xff0c;又去看了原来的GL画线&#xff0c;自己画图思考了一下适配UI的问题&#xff0c;最终解决。 特此说明&#xff0c;GL画线功能&#xff0c;及Shader均为借鉴&#xff0c;自己做了优化。…

GL823K

下面是另一家SD/TF解码芯片的方案 ![](https://img-blog.csdnimg.cn/20210319145313645.png?x-oss-processimage/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80OTU3MDgwNA,size_16,color_FFFFFF,t_70 13030533945 VX

GL各个表结构总结

NewProgramer EBS GL表结构学习(转) gl_code_combinations&#xff1a;科目组合 字段名 含义 备注 code_combination_id 主键&#xff0c;科目编码ID&#xff0c;自动编号 segment1 分行代码 setgment2 是受益部门 segment3 科目代码 segment4 产品…

初识mapbox GL

一、概述 最近由于项目的需求&#xff0c;借此机会对mapbox GL做了一个系统的学习&#xff0c;同时也对整个学习过程做一个记录&#xff0c;一方面留作自用&#xff0c;另一方面也希望看到此文的人在学习mapbox GL的时候&#xff0c;能够有所启发、有所收获。 二、快速认识 …