【MySQL】MVCC(多版本并发控制)详解

MVCC

MVCC概述

MVCC,全称 Multi-Version Concurrency Control ,即多版本并发控制。MVCC 是一种并发控制的方法,一般在数据库管理系统中,实现对数据库的并发访问,在编程语言中实现事务内存。

MVCC就是在ReadCommitted(读已提交)、RepeatableRead(可重复读) 隔离级别,不加锁的情况下,解决并发事务的脏读、幻读和不可重复读问题。

MVCC 在 MySQL InnoDB 中的实现主要是为了提高数据库并发性能,用更好的方式去处理读-写冲突,做到即使有读写冲突时,也能做到不加锁,非阻塞并发读。

什么是当前读、快照读?

当前读: 读到的数据都是最新的数据,像排他锁(又称写锁updateinsertdeleteselect for update共享锁(又称读锁select lock in share mode,这些操作都是当前读。

快照读: 可能读到的并不一定是数据的最新版本,而有可能是之前的历史版本。像不加锁的select操作就是快照读,如果隔离级别是串行化,快照读会退化成当前读。

数据库并发场景

  • 读-读: 不存在任何问题。
  • 读-写: 有线程安全问题,可能出现脏读、幻读、不可重复读。
  • 写-写: 有线程安全问题,可能存在更新丢失等。

MVCC(多版本并发控制)是一种用来解决读-写冲突的无锁并发控制,也就是为事务分配单向增长的时间戳,为每个修改保存一个版本,版本与事务时间戳关联,读操作只读该事务开始前的数据库的快照。

MVCC实现原理

MVCC 的目的就是多版本并发控制,在数据库中的实现,就是为了解决读写冲突,它的实现原理主要是依赖记录中的 3个隐式字段,undo日志版本链 , Read View 来实现的。

三个隐式字段

数据库中的每行记录都有DB_TRX_ID(事务id)DB_ROLL_PTR(回滚指针)DB_ROW_ID(隐藏主键)这三个字段。

DB_TRX_ID(事务id)DB_ROLL_PTR(回滚指针)DB_ROW_ID(隐藏主键)
记录创建这条记录,最后一次修改该记录事务的ID。每处理一个事务,其值自动 +1回滚指针,指向这条记录的上一个版本(存储于 rollback segment 里)隐含的自增 ID(隐藏主键),如果数据表没有主键,InnoDB 会自动以DB_ROW_ID产生一个聚簇索引

undo日志版本链

undo日志版本链是指一行数据被多个事务依次修改过后,在每个事务修改完后,Mysql会保留修改前的数据undo回滚日志,并且用两个隐藏字段DB_TRX_ID(事务id)DB_ROLL_PTR(回滚指针)把这些undo日志串联起来形成一个历史记录版本链。

undo日志分类:

undo log 主要分为两种:

  • insert undo log 代表事务在 insert 新记录时产生的 undo log,只在事务回滚时需要,并且在事务提交后可以被立即丢弃
  • update undo log 事务在进行 updatedelete时产生的 undo log ;不仅在事务回滚时需要,在快照读时也需要;所以不能随便删除,只有在快速读或事务回滚不涉及该日志时,对应的日志才会被 purge 线程统一清除。
undo日志版本链流程图

1)事务A,在employee表插入了一条数据,name为zhangsan、age为22、主键id为1、事务id为100、回滚指针和隐式主键为null。这条日志会在insert undo log中。

在这里插入图片描述
2)事务B对employee表主键id为1的记录做了修改,修改了name字段为lisi。(在事务B之前都没有事务修改过这条数据)

  • 拷贝改行数据到undo log中,作为旧纪录,既在 undo log 中有当前行的拷贝副本。
  • 修改name字段为lisi,假设事务id自增到101,回滚指针指向拷贝的副本。

在这里插入图片描述

3)事务C对employee表主键id为1的记录做了修改,修改了age字段为18。

  • 在拷贝数据到undo log中,发现这行数据已经有undo日志版本链了。修改后的数据,假设事务id为102。回滚指针就会指向undo日志版本链最后修改的那一条记录。

在这里插入图片描述

Read View 读视图

在可重复读隔离级别,当事务开启,执行任何查询sql时会生成当前事务的一致性视图read-view该视图在事务结束之前永远都不会变化(如果是读已提交隔离级别在每次执行查询sql时都会重新生成read-view)这个视图由执行查询时所有未提交事务id数组(数组里最小的id为min_id)和已创建的最大事务id+1(max_id)组成,事务里的任何sql查询结果需要从对应版本链里的最新数据开始逐条跟read-view做比对从而得到最终的快照结果。

Read View 主要是用来做可见性判断的,可见性算法如下 (trx_id事务id)

绿色部分( trx_id<min_id ):已提交的事务
红色部分( trx_id>max_id ):未开始的事务
黄色部分(min_id <=trx_id<= max_id):活跃的事务。

  1. 如果 row trx_id 落在绿色部分( trx_id<min_id ),表示这个版本是已提交的事务生成的,这个数据是可见的;
  2. 如果 rowtrx_id等于当前事务的trx_id,这个数据是可见的;
  3. 如果 rowtrx_id 落在红色部分( trx_id>=max_id ),表示这个版本是由将来启动的事务生成的,是不可见的;
  4. 如果 rowtrx_id 落在黄色部分(min_id <=trx_id<max_id),那就包括两种情况
    a. 若 rowtrx_id 在视图数组中,表示这个版本是由还没提交的事务生成的,不可见
    b. 若 rowtrx_id 不在视图数组中,表示这个版本是已经提交了的事务生成的,可见

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

关于readview和可见性算法的原理解释

readview和可见性算法其实就是记录了sql查询那个时刻数据库里提交和未提交所有事务的状态。

要实现RR隔离级别,事务里每次执行查询操作readview都是使用第一次查询时生成的readview,也就是都是以第一次查询时当时数据库里所有事务提交状态来比对数据是否可见,当然可以实现每次查询的可重复读的效果了。

要实现RC隔离级别,事务里每次执行查询操作readview都会按照数据库当前状态重新生成readview,也就是每次查询都是跟数据库里当前所有事务提交状态来比对数据是否可见,当然实现的就是每次都能查到已提交的最新数据效果了。

RepeatableRead(可重复读)MVCC可见性算法示例

假设有一张account表,account表有主键idnamebalance三个字段。最开始这张表里面的数据是:
在这里插入图片描述

1)事务trx_id = 100,修改了balance字段为200,此时事务100还未提交
2)事务trx_id = 200,修改了balance字段为300,此时事务200还未提交
3)事务trx_id = 300,修改了balance字段为500,此时事务300已经提交

此时的undo log日志版本链如下图:

在这里插入图片描述
4)事务trx_id = 400,执行select语句查询id=1,balance字段的数据,数据库为该行数据生成一个Read View读视图,假设数据看没有其它事务了,此时的readview数组:[100,200],min_id:100,max_id:400+1 = 401

此时的row最新的trx_id为300,因为事务400未作修改操作。从undo log日志版本链最后修改的,一直往上查询。根据上面的可见性算法分析:

  1. 先判断trx_id<min_id(300<100)不满足条件
  2. 再判断trx_id=create_trx_id(当前事务id),(300=400)不满足条件
  3. 再判断trx_id>=max_id(300>=401)不满足条件
  4. 再判断min_id <=trx_id<max_id(100<=300<401)满足条件
  5. trx_id=300,很显然不在readview数组[100,200]中,可见

得出结论:事务400查询的数据balance字段为500

5)事务trx_id = 200,又修改了balance字段为800,此时事务200已提交

此时的undo log日志版本链如下图:

在这里插入图片描述

6)事务trx_id = 400,又执行select语句查询id=1,balance字段的数据。在可重复读隔离级别下,不会重新生成Read View读视图,还是用的之前的Read View读视图。此时的readview数组:[100,200],min_id:100,max_id:400+1 = 401

此时的row最新的trx_id为200,同步骤4分析:

  1. 先判断trx_id<min_id(200<100)不满足条件
  2. 再判断trx_id=create_trx_id(当前事务id)(200=400)不满足条件
  3. 再判断trx_id>=max_id(200>=401)不满足条件
  4. 再判断min_id <=trx_id<max_id(100<=200<401)满足条件
  5. trx_id=200,很显然在readview数组[100,200]中,不可见

上面判断出最新修改的undo log日志不满足,继续往上查询,同理可以推断出,事务400查询的数据balance字段为500

ReadCommitted(读已提交)MVCC可见性算法示例

读已提交和可重复读是类似的,读已提交就是每次执行select,就会重新生成Read View读视图。

上面的我就不复制了,唯一不同的就是步骤6,

6)事务trx_id = 400,又执行select语句查询id=1,balance字段的数据。当前的活跃事务就只剩下事务100了,此时的readview数组:[100],min_id:100,max_id:400+1 = 401

此时的row最新的trx_id为200:

  1. 先判断trx_id<min_id(200<100)不满足条件
  2. 再判断trx_id=create_trx_id(当前事务id),(200=400)不满足条件
  3. 再判断trx_id>=max_id(200>=401)不满足条件
  4. 再判断min_id <=trx_id<max_id(100<=200<401)满足条件
  5. trx_id=200,很显然在readview数组[100,200]中,可见

得出结论:事务400查询的数据balance字段为800

参考文章:
【MySQL笔记】正确的理解MySQL的MVCC及实现原理

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

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

相关文章

车载通信架构 —— 新车载总线类型下(以太网)的通信架构

我是穿拖鞋的汉子&#xff0c;魔都中坚持长期主义的汽车电子工程师。 老规矩&#xff0c;分享一段喜欢的文字&#xff0c;避免自己成为高知识低文化的工程师&#xff1a; 屏蔽力是信息过载时代一个人的特殊竞争力&#xff0c;任何消耗你的人和事&#xff0c;多看一眼都是你的不…

HTTP四种请求方式,状态码,请求和响应报文

1.get请求 一般用于获取数据请求参数在URL后面请求参数的大小有限制 2.post请求 一般用于修改数据提交的数据在请求体中提交数据的大小没有限制 3.put请求 一般用于添加数据 4.delete请求 一般用于删除数据 5.一次完整的http请求过程 域名解析&#xff1a;使用DNS协议…

如何进行手动脱壳

脱壳的目的就是找到被隐藏起来的OEP&#xff08;入口点&#xff09; 这里我一共总结了三种方法&#xff0c;都是些自己的理解希望对你们有用 单步跟踪法 一个程序加了壳后&#xff0c;我们需要找到真正的OEP入口点&#xff0c;先运行&#xff0c;找到假的OEP入口点后&#x…

SSD主控

《深入浅出SSD》学习中… 文章目录 《深入浅出SSD》学习中.....一、SSD主控二、PCIe和NVMe控制器前端子系统1.PCIe控制器2.NVMe控制器 一、SSD主控 就是类似电脑CPU的东西&#xff0c;在SSD中收取处理Host端的命令&#xff0c;管理NAND闪存 二、PCIe和NVMe控制器前端子系统 主…

深度学习之基于CT影像图像分割检测系统

欢迎大家点赞、收藏、关注、评论啦 &#xff0c;由于篇幅有限&#xff0c;只展示了部分核心代码。 文章目录 一项目简介 二、功能三、系统四. 总结 一项目简介 基于CT影像的图像分割检测系统可以被设计成能够自动地检测出CT图像中的病变部位或解剖结构&#xff0c;以协助医生进…

4种经典的限流算法与集群限流

0、基础知识 1000毫秒内&#xff0c;允许2个请求&#xff0c;其他请求全部拒绝。 不拒绝就可能往db打请求&#xff0c;把db干爆~ interval 1000 rate 2&#xff1b; 一、固定窗口限流 固定窗口限流算法&#xff08;Fixed Window Rate Limiting Algorithm&#xff09;是…

自定义歌曲试听SeekBar

看到这个效果&#xff0c;可能会想到完全自定义一个控件&#xff0c;其实我们在系统Seekbar的基础上&#xff0c;将progressDrawable中progress背景设为透明后&#xff0c;叠加绘制试听状态下的进度区域即可 class PlayerSeekBar JvmOverloads constructor(context: Context,a…

等级保护建设全流程

等保&#xff0c;全称为信息安全等级保护&#xff0c;是对信息和信息载体按照重要性等级分级进行保护的一种工作。 企业的信息系统有收集、储存用户信息的&#xff0c;都需要进行等保建设&#xff0c;以此来整改提升系统的安全防护能力&#xff0c;降低被攻击的风险。若不然一旦…

全志R128内存泄漏调试案例

内存泄露调试案例 问题背景 硬件&#xff1a;R128 软件&#xff1a;FreeRTOS rtplayer_test(Cedarx) AudioSystem 问题复现 复现步骤&#xff1a; rtplayer_test /data/boot.mp3串口输入"l", 循环播放串口输入"b" , 播放器后台执行 具体表现 rtpla…

Re50:读论文 Large Language Models Struggle to Learn Long-Tail Knowledge

诸神缄默不语-个人CSDN博文目录 诸神缄默不语的论文阅读笔记和分类 论文名称&#xff1a;Large Language Models Struggle to Learn Long-Tail Knowledge ArXiv网址&#xff1a;https://arxiv.org/abs/2211.08411 官方GitHub项目&#xff08;代码和实体&#xff09;&#xf…

找不到msvcp110.dll怎么办,msvcp110.dll丢失的修复方法

您可能已经碰见过这样的情况&#xff0c;当您试图打开某个软件时&#xff0c;屏幕上突然跳出一个提示窗口&#xff0c;告诉您 “找不到msvcp110.dll”&#xff0c;“msvcp110.dll丢失”。遇到这种情况是不是让人很焦头烂额呀&#xff1f;别担心&#xff0c;接下来我就为您提供几…

【EI会议征稿】第三届能源利用与自动化国际学术会议(ICEUA 2024)

第三届能源利用与自动化国际学术会议&#xff08;ICEUA 2024&#xff09; 2024 3rd International Conference on Energy Utilization and Automation (ICEUA 2024) 2024年第三届能源利用与自动化国际学术会议&#xff08;ICEUA 2024&#xff09;将于2024年3月15-17日在中国武汉…

C++ 调用 Lua 函数

零、前言 Lua 作为一门脚本语言&#xff0c;可以作为 “配置文件”、“动态逻辑脚本” 等角色作用于宿主程序。 因为他是一门语言&#xff0c;所以他有以下的好处&#xff1a; 1. Lua 会处理语法细节&#xff0c;后续维护简单&#xff0c;并且可以有注释。 2. 可以编写逻辑&…

IDEA 快捷键汇总

目录 1、altinsert 2、ctrl/ 3、altenter 4、alt回车 5、ctrlD 6、ctrlaltL 7、ctrl点击 8、alt左键向下拉 9、ctrlaltv 10、ctrlaltwint 1、altinsert 快速创建代码&#xff0c;可以快速创建类中get set tostring等方法 2、ctrl/ 单行注释 3、altenter…

水库大坝安全监测系统守护水利工程安全的坚实后盾

WX-WY1 随着社会经济的发展和科技的进步&#xff0c;水利工程的安全问题越来越受到人们的关注。水库大坝作为水利工程的重要组成部分&#xff0c;其安全状况直接关系到周边地区人民的生命财产安全和生态环境。因此&#xff0c;建立一个高效、可靠的水库大坝安全监测系统至关重要…

特效!视频里的特效在哪制作——Adobe After Effects

今天&#xff0c;我们来谈谈一款在Adobe系列中推出的一款图形视频处理软件&#xff0c;适用于从事设计和视频特技的机构&#xff0c;包括电视台、动画制作公司、个人后期制作工作室以及多媒体工作室的属于层类型后期软件——Adobe After Effects。 Adobe After Effects&#xf…

qt槽函数的四种写法

槽函数的四种写法 一,Qt4写法 不推荐这种写法,如果SLGNAL写错了,或者信号名字,槽函数名字写错了.编译器检查不出来,导致程序无响应,引起不必要的误解 connect(ui.btnOpen,SLGNAL(clicked),this,SLOT(open()));二,Qt5写法 推荐使用这种写法&#xff0c;信号名字、槽函数名字…

gitlab利用CI多工程持续构建

搭建CI的过程中有多个工程的时候&#xff0c;一个完美的构建过程往往是子工程上的更新(push 或者是merge)触发父工程的构建&#xff0c;这就需要如下建立一个downstream pipeline 子仓库1 .gitlab-ci.yml stages:- buildbuild_job:stage: buildtrigger:project: test_user/tes…

-bash: jps: command not found

背景 服务器的jdk通过yum 安装的&#xff0c;要用jps查询pid&#xff0c;提示找不到命令 yum install -y java-1.8.0-openjdk.x86_64 一、jps命令无法找到 [devhgh-tob-hsbc-dev-003 ~]$ jps -bash: jps: command not found 二、检查基础Java环境 [devhgh-tob-hsbc-dev-003 ~]…

计算机是如何工作的(简单介绍)

目录 一、冯诺依曼体系 二、CPU基本流程工作 逻辑⻔ 电⼦开关——机械继电器(Mechanical Relay) ⻔电路(Gate Circuit) 算术逻辑单元 ALU&#xff08;Arithmetic & Logic Unit&#xff09; 算术单元(ArithmeticUnit) 逻辑单元(Logic Unit) ALU 符号 寄存器(Regis…