一文精通MVCC机制

article/2025/9/15 12:46:56

MVCC(Multi-Version Concurrency Control)多版本并发控制机制

使用串行化隔离级别时,mysql会将所有的操作加锁互斥,来保证并发安全。这种方式必然降低并发性能。mysql在读已提交可重复读隔离级别下,对一行数据的读和写两个操作默认是不会通过加锁互斥来保证隔离性,避免了频繁加锁互斥。那么具体是如何实现的呢?首先要了解两个概念。

准备

建表语句

CREATE TABLE `product` ( `id` int NOT NULL AUTO_INCREMENT, `name` varchar(255) DEFAULT NULL, `price` int DEFAULT NULL, PRIMARY KEY (`id`)) ENGINE=InnoDB AUTO_INCREMENT=21 DEFAULT CHARSET=utf8;

undo日志版本链

  1. 我们向product表插入一条数据

INSERT INTO mysql_demo.product (id, name, price) VALUES (1, 'apple', 10);

此时mysql会同时向undo日志里写入一条记录。 trx_id为插入操作的事务id。这里随便写了一个80,意思一下。 roll_pointer后面再说。

  1. 这时候又来了一个事务,对数据进行了修改。比如事务id 300,修改price为20。此时mysql同样会在undo日志里写入一条记录。并且roll_pointer会指向前一条记录

  1. 以此类推,后续又有新的事务来操作这条记录,就会形成一条版本链,这条链就是undo日志版本链

每条数据对应着有一个undo日志版本链。

对于insert和update操作,mysql会向undo日志里添加一条记录。select操作不会产生记录。

对于删除的情况可以认为是update的特殊情况,会将版本链上最新的数据复制一份,然后将trx_id修改成删除操作的trx_id,同时在该条记录的头信息(record header)里的(deleted_flag)标记位写上true,来表示当前记录已经被删除,在查询时按照上面的规则查到对应的记录如果delete_flag标记位为true,意味着记录已被删除,则不返回数据。

在来看下什么是read view。

一致性试图read view机制

read view的生成

  • 可重复读隔离级别:事务开启后,首次执行任何select时会生成当前事务的read-view,在事务结束前不会变化。

  • 读已提交隔离级别:事务开启后,每次执行select时都会重新生成read-view。

read view的组成

这个视图由执行查询时所有未提交事务id数组(数组里最小的id为min_id)已创建的最大事务id(max_id)组成。

我们来举个例子。

  1. Transaction 80: 开启事务,插入一条记录。并且commit;

  1. Transaction 100:开启事务,执行update。生成事务id 100。这里需要注意begin和select不会生成事务id,所以加了一条无关的update,生成事务id。update内容可以忽略。

begin/start transaction 命令并不是一个事务的起点,在执行到它们之后的第一个修改操作InnoDB表的语句,事务才真正启动,才会向mysql申请事务id

mysql内部是严格按照事务的启动顺序来分配事务id的

  1. Transaction 200:同上

  1. Transaction 300:把价格修改成20了。并且commit了。

  1. select 1: select 不生成事务id。 事务开启后,首次执行任何select时会生成当前事务的read-view。

  1. Transaction 400:把价格修改成18了。

read view的组成 = 未提交事务id数组(数组里最小的id为min_id) + 已创建的最大事务id(max_id)组成

此时未提交事务id有100,200(80 已经提交了)。最小的id为100。 已创建的最大事务id为300。(注意read view 是在第5步生成的,此时还没有Transaction 400)

因此 read view为[100,200],300 min_id为100 ,max_id为300。 [100,200] 为视图数组。

此时对应的undo日志版本链如下

那么read view 的作用是什么呢?

read view的作用

根据上面的结果,我们可以将事务进行分类。因为事务的id是有序递增的。所以我们可以得出以下结论

  • 因为未提交事务的最小id(min_id)为100,所以小于100的事务都是已提交的。( Transaction 80)

  • 因为已创建的最大事务id(max_id)为300,所以大于300的区域都是未开启事务。 (Transaction 400) 未开启理解为在执行select的时候没有开启。

  • 介于min_id和max_id之间的事务,包含了未提交和已提交的事务。 (Transaction 100,200,300)

那么mysql是如何通过read view和undo日志版本链实现并发事务之间的隔离的呢?那就需要看下版本链比对规则了。

版本链比对规则

事务里的每一条select都需要从对应版本链里的最新数据开始逐条跟read-view做比对,按照比对规则得到最终的快照结果。下面我们来看下版本链比对规则。

  1. 如果 row 的 trx_id 落在绿色部分( trx_id

  1. 如果 row 的 trx_id 落在灰色部分( trx_id>max_id ),表示这个版本是由将来启动的事务生成的

  1. row 的 trx_id 就是当前自己的事务是可见的;

  1. 否则不可见;

  1. 如果 row 的 trx_id 落在黄色部分(min_id <=trx_id<= max_id),那就包括两种情况

  1. 若 row 的 trx_id 在视图数组中,表示这个版本是由还没提交的事务生成的,

  1. 若 row 的 trx_id 就是当前自己的事务是可见的

  1. 否则不可见;

  1. 若 row 的 trx_id 不在视图数组中,表示这个版本是已经提交了的事务生成的,可见。

知道了版本链的比对规则,下面我们通过实例来看下,mysql的MVCC机制是如何工作的。

实战演练

可重复读Repeatable-Read(RR)

我们先以可重复读Repeatable-Read(RR)为例

可重复读隔离级别:事务开启后,首次执行任何select时会生成当前事务的read-view,在事务结束前不会变化。

案例一

我们先以上面的情况为例来进行分析。此时的情况如下:

  • read view为 [100,200],300

  • undo日志版本链如下

  • 套用版本链比对规则

  1. 首先在版本链中找到最新数据。

  1. Transaction 300,trx_id = max_id。此时继续比对, trx_id 不在视图数组中,可见

  1. 返回Transaction 300记录的数据信息。price = 20;

案例二

Transaction 400,在第10行执行了一次update。

Transaction 100,在第11,12行执行了两次update。然后select 1 13行执行了一次select。 我们来分析下这个select。

  • 因为RR隔离级别首次执行任何select时会生成当前事务的read-view,在事务结束前不会变化。所以read view为 [100,200],300。没有变化。

  • undo日志版本链如下

  • 套用版本链比对规则

  1. 首先在版本链中找到最新数据。

  1. Transaction 100,trx_id = min_id。继续分析 trx_id 在视图数组中,表示这个版本是由还没提交的事务生成的,不可见。

  1. 第二行Transaction 100,分析同上

  1. 第三行Transaction 400, trx_id > max_id,不可见。

  1. Transaction 300,trx_id = max_id。此时继续比对,trx_id 不在视图数组中,可见

  1. 返回Transaction 300记录的数据信息。price = 20;

案例三

继续向下Transaction 100,在第15行commit。Transaction 200,在第15,16行执行了两次update。然后select1 17行执行了一次select。 我们来分析下这个select。

  • 因为RR隔离级别首次执行任何select时会生成当前事务的read-view,在事务结束前不会变化。所以read view为 [100,200],300。没有变化。

  • undo日志版本链如下

  • 套用版本链比对规则

  1. 首先在版本链中找到最新数据。

  1. Transaction 200,min_id < trx_id < max_id。继续分析 trx_id 在视图数组中,表示这个版本是由还没提交的事务生成的,不可见。

  1. 下一行Transaction 200,分析同上.

  1. Transaction 100,trx_id = min_id。继续分析 trx_id 在视图数组中,表示这个版本是由还没提交的事务生成的,不可见。

  1. 下一行Transaction 100,分析同上。

  1. 下一行Transaction 400, trx_id > max_id,不可见。

  1. Transaction 300,trx_id = max_id。此时继续比对,trx_id 不在视图数组中,可见

  1. 返回Transaction 300记录的数据信息。price = 20;

案例四

继续select2 17行执行了一次select。 我们来分析下这个select。

  • RR隔离级别首次执行任何select时会生成当前事务的read-view。read view为 [200,400],400。

  • undo日志版本链如下

  • 套用版本链比对规则

  1. 首先在版本链中找到最新数据。

  1. Transaction 200,trx_id = min_id。继续分析 trx_id 在视图数组中,表示这个版本是由还没提交的事务生成的,不可见。

  1. 下一行Transaction 200,分析同上.

  1. Transaction 100,trx_id < min_id。表示这个版本是已提交的事务生成的,这个数据是可见的;

  1. 返回 price = 16。

案例五

我们再来看一下如果select1 如果有update操作(update操作会创建事务id,我们假设是 500)。Transaction 500 此时是如何读取到更新后的数据的。

来分析下15行。

  • RR隔离级别首次执行任何select时会生成当前事务的read-view,在事务结束前不会变化。read view为 [100,200],300。

  • undo日志版本链如下

  • 套用版本链比对规则

  1. 首先在版本链中找到最新数据。

  1. Transaction 400,trx_id > max_id(read view是第一次select时生成的,此时max_id仍然是 300)。表示这个版本是由将来启动的事务生成的,是不可见的

  1. Transaction 500,trx_id > max_id。表示这个版本是由将来启动的事务生成的,但row 的 trx_id 就是当前自己的事务是可见的;所以可见

  1. 返回 price = 8。

结论:通过以上案例,我们可以知道。 MVCC机制在RR中首次查询时会固定read view。后续和其他事务隔离开了,其他事务对数据的操作不会影响到当前事务。

读已提交Read-Committed(RC)

我们再以读已提交Read-Committed(RC)为例

读已提交隔离级别:事务开启后,每次执行select时都会重新生成read-view。

案例一

第9行没有变化,我们来看第13行。

read view的组成 = 未提交事务id数组(数组里最小的id为min_id) + 已创建的最大事务id(max_id)组成

未提交事务id数组 100,200,400 ; min_id 100 ; max_id 400

  • read view为 [100,200,400],400。

  • undo日志版本链如下

  • 套用版本链比对规则

  1. 首先在版本链中找到最新数据。

  1. Transaction 100,trx_id = min_id。继续分析 trx_id 在视图数组中,表示这个版本是由还没提交的事务生成的,不可见。

  1. 下一行Transaction 100,分析同上.

  1. Transaction 400, trx_id = max_id。继续分析 trx_id 在视图数组中,表示这个版本是由还没提交的事务生成的,不可见。

  1. Transaction 300,min_id < trx_id< max_id。不在视图数组中,表示这个版本是已经提交了的事务生成的,可见。

  1. 返回 price = 20。

案例二

来看第17行。

read view的组成 = 未提交事务id数组(数组里最小的id为min_id) + 已创建的最大事务id(max_id)组成

未提交事务id数组 200,400 ; min_id 200 ; max_id 400

  • read view为 [200,400],400。

  • undo日志版本链如下

  • 套用版本链比对规则

  1. 首先在版本链中找到最新数据。

  1. Transaction 200, trx_id = min_id。继续分析 trx_id 在视图数组中,表示这个版本是由还没提交的事务生成的,不可见。

  1. 同上

  1. Transaction 100, trx_id

  1. 返回 price = 16。

OK,就分析到这里吧。希望对你有所帮助!

读已提交Read-Committed(RC)

我们再以读已提交Read-Committed(RC)为例

读已提交隔离级别:事务开启后,每次执行select时都会重新生成read-view。

案例一

第9行没有变化,我们来看第13行。

read view的组成 = 未提交事务id数组(数组里最小的id为min_id) + 已创建的最大事务id(max_id)组成

未提交事务id数组 100,200,400 ; min_id 100 ; max_id 400

  • read view为 [100,200,400],400。

  • undo日志版本链如下

  • 套用版本链比对规则

  1. 首先在版本链中找到最新数据。

  1. Transaction 100,trx_id = min_id。继续分析 trx_id 在视图数组中,表示这个版本是由还没提交的事务生成的,不可见。

  1. 下一行Transaction 100,分析同上.

  1. Transaction 400, trx_id = max_id。继续分析 trx_id 在视图数组中,表示这个版本是由还没提交的事务生成的,不可见。

  1. Transaction 300,min_id < trx_id< max_id。不在视图数组中,表示这个版本是已经提交了的事务生成的,可见。

  1. 返回 price = 20。

案例二

来看第17行。

read view的组成 = 未提交事务id数组(数组里最小的id为min_id) + 已创建的最大事务id(max_id)组成

未提交事务id数组 200,400 ; min_id 200 ; max_id 400

  • read view为 [200,400],400。

  • undo日志版本链如下

  • 套用版本链比对规则

  1. 首先在版本链中找到最新数据。

  1. Transaction 200, trx_id = min_id。继续分析 trx_id 在视图数组中,表示这个版本是由还没提交的事务生成的,不可见。

  1. 同上

  1. Transaction 100, trx_id

  1. 返回 price = 16。

OK,就分析到这里吧。希望对你有所帮助!


http://chatgpt.dhexx.cn/article/7Eyvua9k.shtml

相关文章

数据库的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;能够有所启发、有所收获。 二、快速认识 …

支持Genero BDL 4gl语言的编辑器

内测版本出来啦。点此下载: FglDeveloper v1.0 →此版本已下架 还有bug,分享几张截图 模板产生器&#xff1a; 画面产生器&#xff1a; 编辑器各种变量提醒 详细功能小伙伴们下载后体验。

TOPGP5.3:导入jar包并在4GL中引用

查看环境$CLASSPATH 上传引用到的JAR包到以下目录 /u1/topprod/tiptop/ds4gl2/bin/javaad/jar 以上为GP5.3目录&#xff0c;其他版本系统可根据查看到的$CLASSPATH上传到相应目录设置环境变量 GP5.3系统中&#xff0c;$CLASSPATH环境变量的设置存在下图文件中&#xff1a; …

4gl调用WEB API,实现JSON传递(Demo)

测试环境: GP5.25 , fjs版本2.32,解析json所需要的jar依赖包 (PS: 如果没有记错是fjs2.32版本及以上才支持java bridge,所以GP 5.25以下的同学就不要用这种方式去测试) 测试内容: 利用此fjs版本对java bridge的支持,实现4gl调用WEB API,实现json传递 测试步骤如下: 1.下载本…

给大家展示一下4gl编辑器

&#xff08;正式版已发布点击下载&#xff09;特地为编辑器开发内置语法解析器&#xff0c;将在代码编辑过程中实时提示代码错误&#xff0c;并且错误提示都是中文显示(楼主英文太垃圾只有做中文了),不再需要频繁上传服务器了哦&#xff0c; 经过楼主努力已经把所有的内置函数…

【实习之T100开发】Genero FGL (TIPTOP4GL) 学习笔记(1)

Genero FGL 学习 Genero FGL 简介Genero FGL 开发&#xff08;编译、连接、执行&#xff09;第一个程序 Hello World变量与运算符变量定义&#xff08;DEFINE&#xff09;预定义变量变量集合&#xff08;RECORD &#xff09;数据结构&#xff08;TYPE&#xff09;变量赋值&…