MVCC原理讲解(深入浅出)

目录

一、什么是MVCC

二、当前读、快照读都是什么鬼

三、当前读 

四、快照读

五、数据库的并发场景

六、MVCC解决并发的哪些问题 

1.解决问题如下:

七、MVCC的实现原理

1.版本链 

八、undo日志

1.undo log 的用途

2.undo log主要分为两种 

 九、Read View(读视图)

1.Read View几个属性

2.Read View可见性判断条件

 十、MVCC和事务隔离级别

十一、RR、RC生成时机

1.解决幻读问题

2.RC、RR级别下的InnoDB快照读区别

 十二、总结


一、什么是MVCC

        全称Multi-Version Concurrency Control,即多版本并发控制,主要是为了提高数据库的并发性能。以下文章都是围绕InnoDB引擎来讲,因为myIsam不支持事务。

        同一行数据平时发生读写请求时,会上锁阻塞住。但mvcc用更好的方式去处理读—写请求,做到在发生读—写请求冲突时不用加锁。

        这个读是指的快照读,而不是当前读,当前读是一种加锁操作,是悲观锁。

        那它到底是怎么做到读—写不用加锁的,快照读和当前读又是什么鬼,跟着你们的贴心老哥,继续往下看。

二、当前读、快照读都是什么鬼

什么是MySQL InnoDB下的当前读和快照读?

三、当前读 

        它读取的数据库记录,都是当前最新的版本,会对当前读取的数据进行加锁,防止其他事务修改数据。是悲观锁的一种操作。

如下操作都是当前读:

  1. select lock in share mode (共享锁)
  2. select for update (排他锁)
  3. update (排他锁)
  4. insert (排他锁)
  5. delete (排他锁)
  6. 串行化事务隔离级别

四、快照读

        快照读的实现是基于多版本并发控制,即MVCC,既然是多版本,那么快照读读到的数据不一定是当前最新的数据,有可能是之前历史版本的数据。

如下操作是快照读:

  • 不加锁的select操作(注:事务级别不是串行化)

快照读与MVCC的关系

答案:MVCCC是“维持一个数据的多个版本,使读写操作没有冲突”的一个抽象概念。

这个概念需要具体功能去实现,这个具体实现就是快照读。(具体实现下面讲)

听完贴心老哥的讲解,是不是瞬间茅厕顿开。

五、数据库的并发场景

  1. 读-读:不存在任何问题,也不需要并发控制
  2. 读-写:有线程安全问题,可能会造成事务隔离性问题,可能遇到脏读,幻读,不可重复读
  3. 写-写:有线程安全问题,可能会存在更新丢失问题,比如第一类更新丢失,第二类更新丢失

六、MVCC解决并发的哪些问题 

        mvcc用来解决读—写冲突的无锁并发控制,就是为事务分配单向增长的时间戳。为每个数据修改保存一个版本,版本与事务时间戳相关联。

读操作只读取该事务开始前的数据库快照。

1.解决问题如下:

  1. 并发读-写时:可以做到读操作不阻塞写操作,同时写操作也不会阻塞读操作。
  2. 解决脏读、幻读、不可重复读等事务隔离问题,但不能解决上面的写-写 更新丢失问题。

因此有了下面提高并发性能的组合拳 :

  1. MVCC + 悲观锁:MVCC解决读写冲突,悲观锁解决写写冲突
  2. MVCC + 乐观锁:MVCC解决读写冲突,乐观锁解决写写冲突 

七、MVCC的实现原理

        它的实现原理主要是版本链,undo日志 ,Read View 来实现的

1.版本链 

        我们数据库中的每行数据,除了我们肉眼看见的数据,还有几个隐藏字段,得开天眼才能看到。分别是db_trx_id、db_roll_pointer、db_row_id。 

db_trx_id:

​         6byte,最近修改(修改/插入)事务ID:记录创建这条记录/最后一次修改该记录的事务ID。

db_roll_pointer(版本链关键):
​         7byte,回滚指针,指向这条记录的上一个版本(存储于rollback segment里)

db_row_id:

​         6byte,隐含的自增ID(隐藏主键),如果数据表没有主键,InnoDB会自动以db_row_id产生一个聚簇索引。

实际还有一个删除flag隐藏字段, 记录被更新或删除并不代表真的删除,而是删除flag变了

        如上图,db_row_id是数据库默认为该行记录生成的唯一隐式主键,db_trx_id是当前操作该记录的事务ID,而db_roll_pointer是一个回滚指针,用于配合undo日志,指向上一个旧版本。

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

        对该记录每次更新后,都会将旧值放到一条undo日志中,就算是该记录的一个旧版本,随着更新次数的增多,所有的版本都会被roll_pointer属性连接成一个链表,我们把这个链表称之为版本链,版本链的头节点就是当前记录最新的值。另外,每个版本中还包含生成该版本时对应的事务id,这个信息很重要,在根据ReadView判断版本可见性的时候会用到。 

八、undo日志

        Undo log 主要用于记录数据被修改之前的日志,在表信息修改之前先会把数据拷贝到undo log里。

当事务进行回滚时可以通过undo log 里的日志进行数据还原。

1.undo log 的用途

  1. 保证事务进行rollback时的原子性和一致性,当事务进行回滚的时候可以用undo log的数据进行恢复。
  2. 用于MVCC快照读的数据,在MVCC多版本控制中,通过读取undo log的历史版本数据可以实现不同事务版本号都拥有自己独立的快照数据版本。

2.undo log主要分为两种 

insert undo log:
​        代表事务在insert新记录时产生的undo log , 只在事务回滚时需要,并且在事务提交后可以被立即丢弃

update undo log(主要):
​        事务在进行update或delete时产生的undo log ; 不仅在事务回滚时需要,在快照读时也需要;

所以不能随便删除,只有在快速读或事务回滚不涉及该日志时,对应的日志才会被purge线程统一清除

 九、Read View(读视图)

        事务进行快照读操作的时候生产的读视图(Read View),在该事务执行的快照读的那一刻,会生成数据库系统当前的一个快照。

        记录并维护系统当前活跃事务的ID(没有commit,当每个事务开启时,都会被分配一个ID, 这个ID是递增的,所以越新的事务,ID值越大),是系统中当前不应该被本事务看到的其他事务id列表。

        Read View主要是用来做可见性判断的, 即当我们某个事务执行快照读的时候,对该记录创建一个Read View读视图,把它比作条件用来判断当前事务能够看到哪个版本的数据,既可能是当前最新的数据,也有可能是该行记录的undo log里面的某个版本的数据。

1.Read View几个属性

  1. trx_ids: 当前系统活跃(未提交)事务版本号集合。
  2. low_limit_id: 创建当前read view 时“当前系统最大事务版本号+1”。
  3. up_limit_id: 创建当前read view 时“系统正处于活跃事务最小版本号”
  4. creator_trx_id: 创建当前read view的事务版本号;

2.Read View可见性判断条件

db_trx_id < up_limit_id || db_trx_id == creator_trx_id(显示)
​        如果数据事务ID小于read view中的最小活跃事务ID,则可以肯定该数据是在当前事务启之前就已经存在了的,所以可以显示。

        或者数据的事务ID等于creator_trx_id ,那么说明这个数据就是当前事务自己生成的,自己生成的数据自己当然能看见,所以这种情 况下此数据也是可以显示的。

db_trx_id >= low_limit_id(不显示)
        如果数据事务ID大于read view 中的当前系统的最大事务ID,则说明该数据是在当前read view 创建之后才产生的,所以数据不显示。 如果小于则进入下一个判断

db_trx_id是否在活跃事务(trx_ids)中

  • 不存在:则说明read view产生的时候事务已经commit了,这种情况数据则可以显示。
  • 已存在:则代表我Read View生成时刻,你这个事务还在活跃,还没有Commit,你修改的数据,我当前事务也是看不见的。

 十、MVCC和事务隔离级别

        上面所讲的Read View用于支持RC(Read Committed,读提交)和RR(Repeatable Read,可重复读)隔离级别的实现。

十一、RR、RC生成时机

  1. RC隔离级别下,是每个快照读都会生成并获取最新的Read View;
  2. 而在RR隔离级别下,则是同一个事务中的第一个快照读才会创建Read View, 之后的快照读获取的都是同一个Read View,之后的查询就不会重复生成了,所以一个事务的查询结果每次都是一样的。 

1.解决幻读问题

  1. 快照读:通过MVCC来进行控制的,不用加锁。按照MVCC中规定的“语法”进行增删改查等操作,以避免幻读。
  2. 当前读:通过next-key锁(行锁+gap锁)来解决问题的。 

2.RC、RR级别下的InnoDB快照读区别

  1. 在RR级别下的某个事务的对某条记录的第一次快照读会创建一个快照及Read View, 将当前系统活跃的其他事务记录起来,此后在调用快照读的时候,还是使用的是同一个Read View,所以只要当前事务在其他事务提交更新之前使用过快照读,那么之后的快照读使用的都是同一个Read View,所以对之后的修改不可见;
  2. 即RR级别下,快照读生成Read View时,Read View会记录此时所有其他活动事务的快照,这些事务的修改对于当前事务都是不可见的。而早于Read View创建的事务所做的修改均是可见
  3. 而在RC级别下的,事务中,每次快照读都会新生成一个快照和Read View, 这就是我们在RC级别下的事务中可以看到别的事务提交的更新的原因 

 十二、总结

        从以上的描述中我们可以看出来,所谓的MVCC指的就是在使用READ COMMITTD、REPEATABLE READ这两种隔离级别的事务在执行普通的SEELCT操作时访问记录的版本链的过程,这样子可以使不同事务的读-写、写-读操作并发执行,从而提升系统性能。 

         

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

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

相关文章

简洁思路推理 KMP 算法——子字符串匹配

例题 28. 找出字符串中第一个匹配项的下标 暴力遍历解法 枚举原串 ss 中的每个字符作为「发起点」&#xff0c;每次从原串的「发起点」和匹配串的「首位」开始尝试匹配&#xff1a; 匹配成功&#xff1a;返回本次匹配的原串「发起点」。 匹配失败&#xff1a;枚举原串的下一个…

UI自动化搭建背景及优劣势分析

经常有人会问&#xff0c;什么样的项目才适合进行UI自动化测试呢&#xff1f;UI自动化测试相当于模拟手工测试&#xff0c;通过程序去操作页面上的控件。而在实际测试过程中&#xff0c;经常会遇到无法找到控件&#xff0c;或者因控件定义变更而带来的维护成本等问题。 哪些场…

Docker—入门及Centos7安装

1、Docker入门 1.1、Docker是什么&#xff1f; Docker是基于Go语言实现的云开源项目。 Docker的主要目标是“Build&#xff0c;Ship&#xff0c;and Run Any App,Anywhere”&#xff0c;也就是通过对应组件的封装、分发、部署、运行等生命周期的管理&#xff0c;使用户的APP&…

docker环境搭建及其安装常用软件

centos安装docker Install Docker Engine on CentOS | Docker Docs 下载docker sudo yum install -y yum-utils sudo yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo sudo yum install -y docker-ce docker-ce-cli containerd.io…

MongoDB本地部署并结合内网穿透实现公网访问本地数据库

文章目录 前言1. 安装数据库2. 内网穿透2.1 安装cpolar内网穿透2.2 创建隧道映射2.3 测试随机公网地址远程连接 3. 配置固定TCP端口地址3.1 保留一个固定的公网TCP端口地址3.2 配置固定公网TCP端口地址3.3 测试固定地址公网远程访问 4. 结语 前言 MongoDB是一个基于分布式文件…

TCP 三次握手 四次挥手以及滑动窗口

TCP 三次握手 简介&#xff1a; TCP 是一种面向连接的单播协议&#xff0c;在发送数据前&#xff0c;通信双方必须在彼此间建立一条连接。所谓的 “ 连接” &#xff0c;其实是客户端和服务器的内存里保存的一份关于对方的信息&#xff0c;如 IP 地址、端口号等。 TCP 可以…

【c语言】详解操作符(下)

前言&#xff1a; 在上文中&#xff0c;我们已经学习了 原码、反码、补码、移位 操作符、移位操作符、位操作符、逗号表达式、下标访问[ ]、函数调用&#xff08; &#xff09;&#xff0c;接下来我们将继续学习剩下的操作符。 1. 结构成员访问操作符 1.1 结构体成员的直接访…

台式电脑的ip地址在哪里找

在网络连接方面&#xff0c;IP地址是非常重要的信息&#xff0c;它是用于标识网络设备的唯一地址。对于台式电脑用户来说&#xff0c;了解自己设备的IP地址是非常有必要的&#xff0c;因为它可以帮助解决网络连接问题&#xff0c;进行远程访问和共享文件等功能。本文将指导读者…

深度学习知识

context阶段和generation阶段的不同 context阶段&#xff08;又称 Encoder&#xff09;主要对输入编码&#xff0c;产生 CacheKV(CacheKV 实际上记录的是 Transformer 中 Attention 模块中 Key 和 Value 的值&#xff09;&#xff0c;在计算完 logits 之后会接一个Sampling 采…

幻兽帕鲁服务器多少钱?4核16G支持32人在线吗?

4核16G服务器是幻兽帕鲁Palworld推荐的配置&#xff0c;阿里云和腾讯云均推出针对幻兽帕鲁的4核16G服务器&#xff0c;阿里云4核16G幻兽帕鲁专属服务器32元1个月、66元3个月&#xff0c;腾讯云4核16G14M服务器66元1个月、277元3个月、1584元一年。云服务器吧yunfuwuqiba.com分享…

vue笔记(一):部署

首 文档 安装 1、安装nodejs&#xff08;链接&#xff09;&#xff0c;18.0以上版本。 2、在想要创建项目的目录下执行命令 npm create vuelatest 按提示创建项目&#xff0c;其中vue router是实现路由功能&#xff0c;pinia实现组件之间共享数据。如果项目需要两个功能建…

python-自动化篇-运维-监控-简单实例-道出如何使⽤Python进⾏网络监控?

如何使⽤Python进⾏⽹络监控&#xff1f; 使⽤Python进⾏⽹络监控可以帮助实时监视⽹络设备、流量和服务的状态&#xff0c;以便及时识别和解决问题。 以下是⼀般步骤&#xff0c;说明如何使⽤Python进⾏⽹络监控&#xff1a; 选择监控⼯具和库&#xff1a;选择适合⽹络监控需…

蓝桥杯省赛无忧 课件49 DFS-剪枝

01 数字王国之军训排队 02 特殊的三角形 03 特殊的多边形

优雅的python(二)

&#x1f308;个人主页&#xff1a;小田爱学编程 &#x1f525; 系列专栏&#xff1a;c语言从基础到进阶 &#x1f3c6;&#x1f3c6;关注博主&#xff0c;随时获取更多关于c语言的优质内容&#xff01;&#x1f3c6;&#x1f3c6; &#x1f600;欢迎来到小田代码世界~ &#x…

【docker】linux系统docker的安装及使用

一、docker应用的安装 1.1 安装方式 Docker的自动化安装&#xff0c;即使用提供的一键安装的脚本&#xff0c;进行安装。 官方的一键安装方式&#xff1a;curl -fsSL https://get.docker.com | bash -s docker --mirror Aliyun 国内 daocloud一键安装命令&#xff1a;curl -s…

二刷代码随想录|Java版|回溯算法1|回溯基础理论+组合问题

理论 写链表之类的真的很痛苦&#xff0c;赶紧跳到回溯&#xff01;这次我想结合算法设计这本书&#xff0c;把java版写出来。放在第三部分吧。希望能够在研一完成这项工作&#xff01; 从一刷总结以下的几个要点&#xff1a; 回溯方法模板性非常强&#xff01;&#xff01;可…

企业虚拟机服务器中了lockbit3.0勒索病毒怎么办,lockbit3.0勒索病毒解密处理流程

对于企业来说&#xff0c;企业的数据是企业的核心命脉&#xff0c;关乎着企业的生产与运营的所有工作。随着网络技术的不断发展&#xff0c;网络安全威胁也在不断增加。近期&#xff0c;云天数据恢复中心接到了很多企业的求助&#xff0c;企业的虚拟机服务器遭到了lockbit3.0勒…

Unity MonoBehaviour 生成dll

dllllllllllllll&#x1f953; &#x1f959;vs创建类库项目&#x1f9c0;添加UnityEngine、UnityEditor引用&#x1f355;添加MonoBehaviour类&#x1f9aa;设置dll生成路径&#x1f37f;生成dll&#x1f354;使用dll中的Mono类 &#x1f959;vs创建类库项目 &#x1f9c0;添加…

Nginx进阶篇【五】

Nginx进阶篇【五】 八、Nginx实现服务器端集群搭建8.1.Nginx与Tomcat部署8.1.1.环境准备(Tomcat)8.1.1.1.浏览器访问:8.1.1.2.获取动态资源的链接地址:8.1.1.3.在Centos上准备一个Tomcat作为后台web服务器8.1.1.4.准备一个web项目&#xff0c;将其打包为war8.1.1.5.启动tomcat进…

基于GPT3.5逆向 和 本地Bert-Vits2-2.3 的语音智能助手

文章目录 一、效果演示二、操作步骤三、架构解析 一、效果演示 各位读者你们好&#xff0c;我最近在研究一个语音助手的项目&#xff0c;是基于GPT3.5网页版的逆向和本地BertVits2-2.3 文字转语音&#xff0c;能实现的事情感觉还挺多&#xff0c;目前实现【无需翻墙&#xff0…