MySQL MVCC原理

news2024/11/26 5:29:30

        全称Multi-Version Concurrency Control,即多版本并发控制,主要是为了提高数据库的并发性能。

1、版本链

        对于使用InnoDB存储引擎的表来说,它的聚簇索引记录中都包含两个必要的隐藏列:

1、trx_id:每次一个事务对某条聚簇索引记录进行改动时,都会把该事务的事务id赋值给trx_id隐藏列。
2、roll_pointer:每次对某条聚簇索引记录进行改动时,都会把旧的版本写入到undo日志中,然后这个隐藏列就相当于一个指针,可以通过它来找到该记录修改前的信息。

        为了实现事务的原子性,InnoDB存储引擎在实际进行增、删、改一条记录时,都需要先把对应的undo日志记下来。

事务id为10的事务,插入一条数据

事务30和事务50分别对这条数据进行修改操作

         每次对记录进行改动,都会记录一条undo日志,每条undo日志也都有一个roll_pointer属性(INSERT操作对应的undo日志没有该属性,因为该记录并没有更早的版本),可以将这些undo日志都连起来,串成一个链表:

        对该记录每次更新后,都会将旧值放到一条undo日志中,就算是该记录的一个旧版本,随着更新次数的增多,所有的版本都会被roll_pointer属性连接成一个链表,我们把这个链表称之为版本链,版本链的头节点就是当前记录最新的值。另外,每个版本中还包含生成该版本时对应的事务id。于是可以利用这个记录的版本链来控制并发事务访问相同记录的行为,那么这种机制就被称之为多版本并发控制(Mulit-Version Concurrency Control MVCC)。 

2、ReadView

ReadView中主要包含4个比较重要的内容:
m_ids:表示在生成ReadView时当前系统中活跃的读写事务的事务id列表。
min_trx_id:表示在生成ReadView时当前系统中活跃的读写事务中最小的事务id,也就是m_ids中的最小值。
max_trx_id:表示生成ReadView时系统中应该分配给下一个事务的id值。注意max_trx_id并不是m_ids中的最大值,事务id是递增分配的。比方说现在有id为1,2,3这三个事务,之后id为3的事务提交了。那么一个新的读事务在生成ReadView时,m_ids就包括1和2,min_trx_id的值就是1,max_trx_id的值就是4。
creator_trx_id:表示生成该ReadView的事务的事务id。

2.1、使用读已提交解决脏读

        此隔离级别的事务在每次查询开始时都会生成一个独立的ReadView。在MuSQL中读已提交和可重复的很大一个区别就是ReadView的生成时机不同。

        假设现在表 table 中只有一条由事务id为10的事务插入的一条记录。
读已提交 —— 每次读取数据前都生成一个ReadView:
        现在系统里有两个事务id分别为80、120的事务在执行。

 

第1次select的时间点

执行过程 

        在执行SELECT语句时会先生成一个ReadView:

        ReadView的m_ids列表的内容就是[80, 120],min_trx_id为80,max_trx_id为121。

        然后从版本链中挑选可见的记录,从图中可以看出,最新版本的列data的内容是 '222',该版本的trx_id值为80,在m_ids列表内,所以不符合可见性要求(trx_id属性值在ReadView的min_trx_id和max_trx_id之间说明创建ReadView时生成该版本的事务还是活跃的,该版本不可以被访问;如果不在,说明创建ReadView时生成该版本的事务已经被提交,该版本可以被访问),根据roll_pointer跳到下一个版本。

        下一个版本的列data的内容是'111',该版本的trx_id值也为80,也在m_ids列表内,所以也不符合要求,继续跳到下一个版本。下一个版本的列data的内容是'xx',该版本的trx_id值为10,小于ReadView中的min_trx_id值,所以这个版本是符合要求的,最后返回给用户的版本就是这条列data为'xx'的记录。

        所以有了这种机制,就不会发生脏读问题!因为会去判断活跃版本,必须是不在活跃版本的才能用,不可能读到没有commit的记录。

 不可重复读问题

        然后,我们把事务id为80的事务提交一下,然后再到事务id为120的事务中更新一下表table中data的记录。

最后版本链

 第二次select

        执行过程:

        在执行SELECT语句时会又会单独生成一个ReadView,该ReadView信息如下:

        m_ids列表的内容就是[120](事务id为80的那个事务已经提交了,所以再次生成快照时就没有它了),min_trx_id为120,max_trx_id为121。

        然后从版本链中挑选可见的记录,从图中可以看出,最新版本的列data的内容是'bbb',该版本的trx_id值为120,在m_ids列表内,所以不符合可见性要求,根据roll_pointer跳到下一个版本。
下一个版本的列data的内容是'aaa',该版本的trx_id值为120,也在m_ids列表内,所以也不符合要求,继续跳到下一个版本。
        下一个版本的列name的内容是'222',该版本的trx_id值为80,小于ReadView中的min_trx_id值120,所以这个版本是符合要求的,最后返回给用户的版本就是这条列name为'222'的记录。

 2.2、使用可重复读级别解决不可重复读问题

        在第一次读取数据时生成一个ReadView

        对于使用REPEATABLE READ隔离级别的事务来说,只会在第一次执行查询语句时生成一个ReadView,之后的查询就不会重复生成了。

        在上面的例子中:

        这个SELECE1的执行过程如下:
        在执行SELECT语句时会先生成一个ReadView:

        ReadView的m_ids列表的内容就是[80, 120],min_trx_id为80,max_trx_id为121。

        然后从版本链中挑选可见的记录,从图中可以看出,最新版本的列data的内容是'222',该版本的trx_id值为80,在m_ids列表内,所以不符合可见性要求(trx_id属性值在ReadView的min_trx_id和max_trx_id之间说明创建ReadView时生成该版本的事务还是活跃的,该版本不可以被访问;如果不在,说明创建ReadView时生成该版本的事务已经被提交,该版本可以被访问),根据roll_pointer跳到下一个版本。
        下一个版本的列data的内容是'111',该版本的trx_id值也为80,也在m_ids列表内,所以也不符合要求,继续跳到下一个版本。
        下一个版本的列data的内容是'xx',该版本的trx_id值为60,小于ReadView中的min_trx_id值,所以这个版本是符合要求的,最后返回给用户的版本就是这条列data为'xx'的记录。

        之后,我们把事务id为80的事务提交一下,然后再到事务id为120的事务中更新一下表table中data的记录。

        这个SELECE2的执行过程如下:

        因为当前事务的隔离级别为可重复读,而之前在执行SELECE1时已经生成过ReadView了,所以此时直接复用之前的ReadView,之前的ReadView的m_ids列表的内容就是[80, 120],min_trx_id为80,max_trx_id为121。

        根据前面的分析,返回的值还是'xx'。

        也就是说两次SELECT查询得到的结果是重复的,记录的列data值都是'xx',这就是可重复读的含义。

2.3、MVCC下的幻读现象和解决

表中只有一条事务10插入的数据

 

 第一次select

        在执行SELECT语句时会先生成一个ReadView:

        m_ids列表的内容就是[80],min_trx_id为80,max_trx_id为81。

        然后从版本链中挑选可见的记录,从图中可以看出,最新版本的列data的内容是'xx',版本的trx_id值为10,可以被当前事务访问,最后返回给用户的版本就是这条列data为'xx'的记录。

第二次select

        因为当前事务的隔离级别为可重复读,而之前在执行SELECE1时已经生成过ReadView了,所以此时直接复用之前的ReadView, m_ids列表的内容就是[80],min_trx_id为80,max_trx_id为81。

        然后从版本链中挑选可见的记录,从图中可以看出,最新版本的列data的内容是'222',版本的trx_id值为120,如果被访问版本的trx_id属性值大于或等于ReadView中的max_trx_id值,表明生成该版本的事务在当前事务生成ReadView后才开启,所以该版本不可以被当前事务访问。

        最终,最后返回给用户的版本还是这条列data为'xx'的记录。这是这种情况下,不会出现幻读现象。

特殊幻读现象:

 此时第一次读是 没有数据,第二次 出现一条数据

 就是第一次读如果是空的情况,且在自己事务中进行了该条数据的修改。

2.4、ReadView中的比较规则

1、如果被访问版本的trx_id属性值与ReadView中的creator_trx_id值相同,意味着当前事务在访问它自己修改过的记录,所以该版本可以被当前事务访问。

2、如果被访问版本的trx_id属性值小于ReadView中的min_trx_id值,表明生成该版本的事务在当前事务生成ReadView前已经提交,所以该版本可以被当前事务访问。

3、如果被访问版本的trx_id属性值大于或等于ReadView中的max_trx_id值,表明生成该版本的事务在当前事务生成ReadView后才开启,所以该版本不可以被当前事务访问。

4、如果被访问版本的trx_id属性值在ReadView的min_trx_id和max_trx_id之间(min_trx_id < trx_id < max_trx_id),那就需要判断一下trx_id属性值是不是在m_ids列表中,如果在,说明创建ReadView时生成该版本的事务还是活跃的,该版本不可以被访问;如果不在,说明创建ReadView时生成该版本的事务已经被提交,该版本可以被访问。

2.5、总结

        MVCC(Multi-Version Concurrency Control ,多版本并发控制)进行普通的SEELCT查询时才生效。

        它指的就是在使用读已提交、可重复读这两种隔离级别的事务在执行普通的SELECT操作时访问记录的版本链的过程,这样子可以使不同事务的读-写、写-读操作并发执行,从而提升系统性能。

        读已提交、可重复读这两个隔离级别的一个很大不同就是:生成ReadView的时机不同,读已提交在每一次进行普通SELECT操作前都会生成一个ReadView,而可重复读只在第一次进行普通SELECT操作前生成一个ReadView,之后的查询操作都重复使用这个ReadView就好了,从而基本上可以避免幻读现象(就是第一次读如果ReadView是空的情况中的某些情况则避免不了)。

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

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

相关文章

connect by prior 递归查询

connect by prior 以公司组织架构举例&#xff0c;共四个层级&#xff0c;总公司&#xff0c;分公司&#xff0c;中心支公司&#xff0c;支公司 总公司level_code为1 下一层级的parent_id为上一层级的id&#xff0c;建立关联关系 SELECT id, name, LEVEL FROM org_info a STA…

区块链学习05-web3中solidity和move语言

Solidity 和 Move 语言的比较&#xff1a;Web3 开发中的两种选择 Solidity 和 Move 都是用于开发区块链平台智能合约的编程语言。它们具有一些相似之处&#xff0c;但也存在一些关键差异。 相似之处: Solidity 和 Move 都是图灵完备语言&#xff0c;这意味着它们可以表达计算…

提高引流精准性的策略

1、定位清晰&#xff1a;明确你的目标用户是谁&#xff0c;了解他们的需求和兴趣&#xff0c;定制内容和策略以吸引他们。 2、价值输出&#xff1a;提供有价值的内容或服务&#xff0c;让用户觉得添加你的微信是有益的&#xff0c;比如独家资讯、优惠券、专业咨询等。 3、筛选…

vs2019 QT无法打开源文件QModbusTcpClient

vs2019无法打开源文件QModbusTcpClient 如果配置的msvc2019,则查找到Include目录 然后包含&#xff1a; #include <QtSerialBus/qmodbustcpclient.h>

PostgreSQl 物化视图

物化视图&#xff08;Materialized View&#xff09;是 PostgreSQL 提供的一个扩展功能&#xff0c;它是介于视图和表之间的一种对象。 物化视图和视图的最大区别是它不仅存储定义中的查询语句&#xff0c;而且可以像表一样存储数据。物化视图和表的最大区别是它不支持 INSERT…

【设计模式】【创建型模式】【02工厂模式】

系列文章 可跳转到下面链接查看下表所有内容https://blog.csdn.net/handsomethefirst/article/details/138226266?spm1001.2014.3001.5501文章浏览阅读2次。系列文章大全https://blog.csdn.net/handsomethefirst/article/details/138226266?spm1001.2014.3001.5501 目录 系…

redis原理之底层数据结构(三)-quicklist

1.绪论 前面讲过的ziplist在查找元素的时候是o(n)的复杂度&#xff0c;如果ziplist长度太长&#xff0c;会导致查找元素很缓慢&#xff0c;而ziplist是拥有内存连续的优势&#xff0c;为了保留ziplist内存连续的优势&#xff0c;但是又不能保留太长的长度&#xff0c;我们出现…

MQ基础1

对应B站视频&#xff1a; MQ入门-01.MQ课程介绍_哔哩哔哩_bilibili 微服务一旦拆分&#xff0c;必然涉及到服务之间的相互调用&#xff0c;目前我们服务之间调用采用的都是基于OpenFeign的调用。这种调用中&#xff0c;调用者发起请求后需要等待服务提供者执行业务返回结果后…

【Linux杂货铺】期末总结篇3:用户账户管理命令 | 组账户管理命令

&#x1f308;个人主页&#xff1a;聆风吟_ &#x1f525;系列专栏&#xff1a;Linux杂货铺、Linux实践室 &#x1f516;少年有梦不应止于心动&#xff0c;更要付诸行动。 文章目录 第五章5.1 ⛳️Linux 账户5.2 ⛳️用户配置文件和目录&#xff08;未完待续&#xff09;5.2.1 …

java面向对象进阶篇--static

一、前言 java进阶篇已经开始了&#xff0c;先从面向对象开始&#xff0c;由于时间原因今天就只更新了static部分&#xff0c;内容上特别详细&#xff0c;一些特别的注意事项也在反复的提醒大家。 温馨提示一下&#xff0c;往后的java篇会越来越难&#xff0c;希望大家能够坚…

推荐5个实用的可视化工具

面对海量的数据&#xff0c;我们应该如何高效地提取其价值&#xff0c;让复杂的信息一目了然&#xff1f;这正是可视化工具大显身手的舞台。今天&#xff0c;我就来分享几款非常好用的数据可视化工具&#xff0c;它们不仅能够帮助你轻松驾驭数据&#xff0c;还能让你的工作汇报…

vite配置环境变量和使用,配置正确后import.meta.env.VITE_APP_BASE_URL编译报错的解决方法

一、配置&#xff1a; 1.新增四个环境文件 .env.development .env.test .env.production .env.pre 内容为不同环境的不同参数变量必须以VITE_APP开头&#xff0c;如&#xff1a; #接口地址 VITE_APP_BASE_URL"&#xffe5;&#xffe5;&#xffe5;&#xffe5;&#xff…

算法 —— 快速幂

目录 P1045 [NOIP2003 普及组] 麦森数 P1226 【模板】快速幂 原理I 原理II P1226 代码解析 P1045 代码解析 P1045 [NOIP2003 普及组] 麦森数 本题来自洛谷&#xff1a;P1045 [NOIP2003 普及组] 麦森数&#xff0c;根据题意&#xff0c;我们可以看到本题需要计算最少2的1…

【Linux】权限的管理和Linux上的一些工具

文章目录 权限管理chgrpchownumaskfile指令sudo指令 目录权限粘滞位Linux中的工具1.软件包管理器yum2.rzsz Linux开发工具vim 总结 权限管理 chgrp 功能&#xff1a;修改文件或目录的所属组 格式&#xff1a;chgrp [参数] 用户组名 文件名 常用选项&#xff1a;-R 递归修改文…

Host碰撞实验

目录 Host碰撞原理 Host碰撞判断技巧 Host碰撞检测方法 Host碰撞实验步骤 从攻击者的视角来进行资产的梳理&#xff0c;采用全端口扫描子域名收集的方式&#xff0c;识别所有的企业资产暴露面。但即使是这样&#xff0c;往往会因为配置错误或是未及时回收等原因&#xff0c…

android13 frameworks里面常用的保存信息或者版本判断的方法

总纲 android13 rom 开发总纲说明 目录 1.前言 2. 数据库 2.1 代码读取用法参考 3.prop 属性配置 3.1 property的key值有哪些特点 4.区别 5. 其他数据存储 6.彩蛋 1.前言 frameworks 不像我们一般开发app那样,很多应用保存的方法都无法使用。这里记录我们系统rom开…

初学SpringMVC之 JSON 篇

JSON&#xff08;JavaScript Object Notation&#xff0c;JS 对象标记&#xff09;是一种轻量级的数据交换格式 采用完全独立于编程语言的文本格式来存储和表示数据 JSON 键值对是用来保存 JavaScript 对象的一种方式 比如&#xff1a;{"name": "张三"}…

ssh -D 选项用于动态(Dynamic)端口转发

举例实现不同ssh连接功能目录 一、功能简介 -D 支持 SOCKS5 协议&#xff0c;可以同时转发 TCP 和 UDP 报文 二、原理介绍 假设拥有三台主机&#xff0c;具体环境如下&#xff1a; 1. 主机 A&#xff1a;本地主机&#xff0c;即 SSH 客户 所在的主机&#xff0c;IP&#xff1…

Python游戏开发——天天酷跑(完整版教程)只需要200行代码就做出了一个天天酷跑小游戏,原来代码做游戏这么简单!零基础也能教你学会!

最近一段时间&#xff0c;小编发现已经好久没有给大家带来趣味游戏的案例展示了。刚好小编趁着周末写了一个《天天酷跑》的游戏&#xff0c;因此拿来跟大家一起分享&#xff0c;和大家一起来重温经典的酷跑游戏。 01 准备开发环境 俗话说&#xff0c;“工欲善其事&#xff0c…

详解:动画专业就业前景和就业方向

随着数字创意产业的蓬勃发展&#xff0c;动画专业已成为越来越多学子的选择。动画专业的就业前景日益广阔&#xff0c;不仅在游戏、影视、广告等传统领域有着广泛应用&#xff0c;还在建筑、教育、医学等多个行业展现出强大的潜力。 那么&#xff0c;何为动画专业呢&#xff1f…