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

一文精通MVCC机制

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,就分析到这里吧。希望对你有所帮助!

相关文章:

一文精通MVCC机制

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

商用ESP32协议采集器源码分享开篇

这是一个关于chatGPT帮助嵌入式程序员开发商业项目的故事. 在开发这个项目的过程中,chatGPT发布了,在它的帮助下,项目开发量减少了10%,所以这个专栏,既是一个关于Micropython开发ESP32的专栏,也是一个程序员在AI的帮助下,提升效率,加速挣钱的案例. 看完之后,你将知道如何用mic…...

代码随想录算法训练营第三十四天 | 860.柠檬水找零,406.根据身高重建队列,452. 用最少数量的箭引爆气球

一、参考资料柠檬水找零https://programmercarl.com/0860.%E6%9F%A0%E6%AA%AC%E6%B0%B4%E6%89%BE%E9%9B%B6.html 根据身高重建队列 https://programmercarl.com/0406.%E6%A0%B9%E6%8D%AE%E8%BA%AB%E9%AB%98%E9%87%8D%E5%BB%BA%E9%98%9F%E5%88%97.html 用最少数量的箭引爆气球ht…...

DDR4介绍01

DDR4&#xff08;第四代双倍数据率同步动态随机存储器SDRAM&#xff09; 关于内存方面知识&#xff0c;大部分人、包括我自己也不是很懂&#xff0c;希望此篇文章能起到点作用&#xff0c;做硬件的就得把相关专业知识学牢了&#xff0c;尤其是专业术语。 下面是DDR4知识做一次…...

扫地机器人行业投资逻辑:国内以价换量元年,海外需求企稳回升

1、国内以价换量元年,投资逻辑由产品迭代转向行业的渗透率提升 2019-2022 年国内扫地机行业主要的投资逻辑是产品迭代的价增带动销额增长。 2019-2022 年国内热销的扫地机产品从单机向自清洁扫地机、全能基站扫地机持续迭 代升级,产品功能日益完善、瞄准用户痛点更新,真正实…...

(考研湖科大教书匠计算机网络)第四章网络层-第七节:IPv4数据报首部格式

获取pdf&#xff1a;密码7281专栏目录首页&#xff1a;【专栏必读】考研湖科大教书匠计算机网络笔记导航 文章目录一&#xff1a;IP数据报首部格式概述二&#xff1a;各字段作用概述&#xff08;1&#xff09;版本&#xff08;2&#xff09;首部长度和可选字段&#xff08;3&am…...

每天10个前端小知识 【Day 18】

前端面试基础知识题 1.如何实现单行&#xff0f;多行文本溢出的省略样式&#xff1f; 在日常开发展示页面&#xff0c;如果一段文本的数量过长&#xff0c;受制于元素宽度的因素&#xff0c;有可能不能完全显示&#xff0c;为了提高用户的使用体验&#xff0c;这个时候就需要…...

【Java集合类】ArrayList

内部结构 ArrayList内部核心是一个Object数组elementDataObject数组的长度&#xff08;length&#xff09;视为ArrayList当前的容量&#xff08;capacity&#xff09;size对象表示ArrayList当前的元素个数 类上的重要注释 内部是Object数组 允许put null值,会自动扩容 size、…...

页面置换算法

页面置换算法 在进程运行过程中&#xff0c;若需要访问的物理块不在内存中&#xff0c;就需要通过一定的方式来将页面载入内存&#xff0c;而此时内存很可能已无空闲空间&#xff0c;因此就需要一定的算法来选择内存中要被置换的页面&#xff0c;这种算法就被称为页面置换算法…...

算法导论【在线算法】—The Ski-Rental Problem、The Lost Cow Problem、The Secretary Problem

算法导论【在线算法】The Ski-Rental Problem问题描述在线算法证明The Lost Cow Problem问题描述在线算法类似问题—寻宝藏The Secretary Problem问题描述在线算法The Best Possible kThe Ski-Rental Problem 问题描述 假设你正在上滑雪课。每节课结束后&#xff0c;你决定&a…...

linux 下怎样给pdf 文件加书签

linux 下怎样给pdf 文件加书签 对于没有书签的pdf文件,怎样给pdf加标签呢? 以方便阅读. 以前总是要借助windows下pdf 工具, 叫什么来者? 忘了 记得是编辑一个用tab表示目录级别的文本文件, 有一种直观的感觉,大目录下嵌套着小目录 ..., 然后导入到文件中 linux 下有没有这种…...

[软件工程导论(第六版)]第2章 可行性研究(课后习题详解)

文章目录1. 在软件开发的早期阶段为什么要进行可行性研究&#xff1f;应该从哪些方面研究目标系统的可行性&#xff1f;2. 为方便储户&#xff0c;某银行拟开发计算机储蓄系统。储户填写的存款单或取款单由业务员输入系统&#xff0c;如果是存款&#xff0c;系统记录存款人姓名…...

[软件工程导论(第六版)]第3章 需求分析(课后习题详解)

文章目录1. 为什么要进行需求分析&#xff1f;通常对软件系统有哪些需求&#xff1f;2. 怎样与用户有效地沟通以获取用户的真实需求&#xff1f;3. 银行计算机储蓄系统的工作过程大致如下&#xff1a;储户填写的存款单或取款单由业务员输入系统&#xff0c;如果是存款则系统记录…...

基于分布鲁棒联合机会约束的能源和储备调度(Matlab代码实现)

&#x1f468;‍&#x1f393;个人主页&#xff1a;研学社的博客 &#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜…...

ETL和数据建模

一、什么是ETL ETL是数据抽取&#xff08;Extract&#xff09;、转换&#xff08;Transform&#xff09;、加载&#xff08;Load &#xff09;的简写&#xff0c;它是将OLTP系统中的数据经过抽取&#xff0c;并将不同数据源的数据进行转换、整合&#xff0c;得出一致性的数据&…...

ccc-pytorch-回归问题(1)

文章目录1.简单回归实战&#xff1a;2.手写数据识别1.简单回归实战&#xff1a; 用 线性回归拟合二维平面中的100个点 公式&#xff1a;ywxbywxbywxb 损失函数&#xff1a;∑(yreally−y)2\sum(y_{really}-y)^2∑(yreally​−y)2 迭代方法&#xff1a;梯度下降法&#xff0c;…...

【JAVA八股文】框架相关

框架相关1. Spring refresh 流程2. Spring bean 生命周期3. Spring bean 循环依赖解决 set 循环依赖的原理4. Spring 事务失效5. Spring MVC 执行流程6. Spring 注解7. SpringBoot 自动配置原理8. Spring 中的设计模式1. Spring refresh 流程 Spring refresh 概述 refresh 是…...

二叉树的相关列题!!

对于二叉树&#xff0c;很难&#xff0c;很难&#xff01;笔者也是感觉很难&#xff01;虽然能听懂课程&#xff0c;但是&#xff0c;对于大部分的练习题并不能做出来&#xff01;所以感觉很尴尬&#xff01;&#xff01;因此&#xff0c;笔者经过先前的那篇博客&#xff0c;已…...

Java设计模式 - 原型模式

简介 原型模式&#xff08;Prototype Pattern&#xff09;是用于创建重复的对象&#xff0c;同时又能保证性能。这种类型的设计模式属于创建型模式&#xff0c;它提供了一种创建对象的最佳方式。 这种模式是实现了一个原型接口&#xff0c;该接口用于创建当前对象的克隆。当直…...

深度学习中的 “Hello World“

Here’s an interesting fact—Each month, there are 186.000 Google searches for the keyword “deep learning.” 大家好✨,这里是bio🦖。每月有超18万的人使用谷歌搜索深度学习这一关键词,是什么让人们对深度学习如此感兴趣?接下来请跟随我来揭开深度学习的神秘面纱。…...

基于大模型的 UI 自动化系统

基于大模型的 UI 自动化系统 下面是一个完整的 Python 系统,利用大模型实现智能 UI 自动化,结合计算机视觉和自然语言处理技术,实现"看屏操作"的能力。 系统架构设计 #mermaid-svg-2gn2GRvh5WCP2ktF {font-family:"trebuchet ms",verdana,arial,sans-…...

Lombok 的 @Data 注解失效,未生成 getter/setter 方法引发的HTTP 406 错误

HTTP 状态码 406 (Not Acceptable) 和 500 (Internal Server Error) 是两类完全不同的错误&#xff0c;它们的含义、原因和解决方法都有显著区别。以下是详细对比&#xff1a; 1. HTTP 406 (Not Acceptable) 含义&#xff1a; 客户端请求的内容类型与服务器支持的内容类型不匹…...

Vue3 + Element Plus + TypeScript中el-transfer穿梭框组件使用详解及示例

使用详解 Element Plus 的 el-transfer 组件是一个强大的穿梭框组件&#xff0c;常用于在两个集合之间进行数据转移&#xff0c;如权限分配、数据选择等场景。下面我将详细介绍其用法并提供一个完整示例。 核心特性与用法 基本属性 v-model&#xff1a;绑定右侧列表的值&…...

智能在线客服平台:数字化时代企业连接用户的 AI 中枢

随着互联网技术的飞速发展&#xff0c;消费者期望能够随时随地与企业进行交流。在线客服平台作为连接企业与客户的重要桥梁&#xff0c;不仅优化了客户体验&#xff0c;还提升了企业的服务效率和市场竞争力。本文将探讨在线客服平台的重要性、技术进展、实际应用&#xff0c;并…...

DIY|Mac 搭建 ESP-IDF 开发环境及编译小智 AI

前一阵子在百度 AI 开发者大会上&#xff0c;看到基于小智 AI DIY 玩具的演示&#xff0c;感觉有点意思&#xff0c;想着自己也来试试。 如果只是想烧录现成的固件&#xff0c;乐鑫官方除了提供了 Windows 版本的 Flash 下载工具 之外&#xff0c;还提供了基于网页版的 ESP LA…...

AI编程--插件对比分析:CodeRider、GitHub Copilot及其他

AI编程插件对比分析&#xff1a;CodeRider、GitHub Copilot及其他 随着人工智能技术的快速发展&#xff0c;AI编程插件已成为提升开发者生产力的重要工具。CodeRider和GitHub Copilot作为市场上的领先者&#xff0c;分别以其独特的特性和生态系统吸引了大量开发者。本文将从功…...

k8s业务程序联调工具-KtConnect

概述 原理 工具作用是建立了一个从本地到集群的单向VPN&#xff0c;根据VPN原理&#xff0c;打通两个内网必然需要借助一个公共中继节点&#xff0c;ktconnect工具巧妙的利用k8s原生的portforward能力&#xff0c;简化了建立连接的过程&#xff0c;apiserver间接起到了中继节…...

JAVA后端开发——多租户

数据隔离是多租户系统中的核心概念&#xff0c;确保一个租户&#xff08;在这个系统中可能是一个公司或一个独立的客户&#xff09;的数据对其他租户是不可见的。在 RuoYi 框架&#xff08;您当前项目所使用的基础框架&#xff09;中&#xff0c;这通常是通过在数据表中增加一个…...

return this;返回的是谁

一个审批系统的示例来演示责任链模式的实现。假设公司需要处理不同金额的采购申请&#xff0c;不同级别的经理有不同的审批权限&#xff1a; // 抽象处理者&#xff1a;审批者 abstract class Approver {protected Approver successor; // 下一个处理者// 设置下一个处理者pub…...

SpringAI实战:ChatModel智能对话全解

一、引言&#xff1a;Spring AI 与 Chat Model 的核心价值 &#x1f680; 在 Java 生态中集成大模型能力&#xff0c;Spring AI 提供了高效的解决方案 &#x1f916;。其中 Chat Model 作为核心交互组件&#xff0c;通过标准化接口简化了与大语言模型&#xff08;LLM&#xff0…...