看一遍就理解:MVCC原理详解

介绍

MVCC(Multi-Version Concurrency Control,多版本并发控制)是一种用于实现数据库并发访问控制的机制。它允许多个用户同时读写同一数据项,从而提高了数据库在高并发环境下的性能和响应速度。以下是具体介绍:

  1. 基本概念
    • MVCC通过为每行数据维护多个版本来工作,每个版本都有自己的创建时间和事务ID。当一个事务需要读取数据时,它会读取对应版本的数据,而不是最新的数据。
    • MVCC避免了使用传统的锁机制来管理数据的并发访问,减少了锁竞争,从而提升了系统的吞吐量和响应时间。
  2. 工作机制
    • MVCC中,每个事务开始时都会创建一个ReadView,这是一个数据快照,记录了当前活跃的所有事务ID。当事务进行查询操作时,它会利用这个快照来判断哪些数据是可见的。
    • 对于INSERT、UPDATE或DELETE操作,系统会创建新的数据版本,并链接到旧版本上形成版本链。每个版本都保存了创建该版本的事务ID和时间戳。
  3. 关键组件
    • 系统中的每个事务都会被分配一个唯一的事务ID。这些ID用于追踪数据的版本以及决定哪些版本对特定事务是可见的。
    • 除了用户定义的数据列外,数据库还会为每个记录维护一些隐藏的元数据列,如行ID、事务ID和回滚指针等。这些信息用于支持MVCC的内部运作。
  4. 隔离级别
    • 在读已提交(READ COMMITTED)和可重复读(REPEATABLE READ)隔离级别下,MVCC通过生成数据的时间点快照来避免脏读、不可重复读和幻读现象的发生。不同的隔离级别决定了事务如何定义它们的ReadView。
  5. 应用场景
    • MVCC特别适用于具有高读/写比率的数据库环境,如联机事务处理系统(OLTP),可以显著提高系统的并发性能和数据一致性。
  6. 优缺点
    • 提高了并发处理能力,减少了等待锁释放的时间。
    • 降低了死锁的风险,因为减少了锁的使用。
    • 增加了系统的复杂性,可能会增加设计和调试的难度。
    • 在某些情况下,可能需要额外的存储空间来保存多版本的数据。

总的来说,MVCC是现代关系型数据库管理系统中一个至关重要的功能,它通过允许并行访问数据的方式来优化数据库的性能。理解其工作原理和实现方式有助于更好地设计和维护数据库应用,特别是在需要处理大量并发事务的环境中。

解决的MySQL问题背景

1.1 什么是数据库事务,为什么要有事务

事务,由一个有限的数据库操作序列构成,这些操作要么全部执行,要么全部不执行,是一个不可分割的工作单位。

假如A转账给B 100 元,先从A的账户里扣除 100 元,再在 B 的账户上加上 100 元。如果扣完A的100元后,还没来得及给B加上,银行系统异常了,最后导致A的余额减少了,B的余额却没有增加。所以就需要事务,将A的钱回滚回去,就是这么简单。

为什么要有事务呢? 就是为了保证数据的最终一致性。

1.2 事务包括哪几个特性?

事务四个典型特性,即ACID,原子性(Atomicity)、一致性(Consistency)、隔离性(Isolation)、持久性(Durability)。

  • 原子性:事务作为一个整体被执行,包含在其中的对数据库的操作要么全部都执行,要么都不执行。
  • 一致性:指在事务开始之前和事务结束以后,数据不会被破坏,假如A账户给B账户转10块钱,不管成功与否,A和B的总金额是不变的。
  • 隔离性:多个事务并发访问时,事务之间是相互隔离的,一个事务不应该被其他事务干扰,多个并发事务之间要相互隔离。。
  • 持久性:表示事务完成提交后,该事务对数据库所作的操作更改,将持久地保存在数据库之中。

1.3 事务并发存在的问题

1.3.1 脏读

当一个事务正在访问数据并且对数据进行了修改,而这种修改还没有提交到数据库中,这时另外一个事务也访问了这个数据,因为这个数据是还没有提交的数据,那么另外一个事务读到的这个数据是“脏数据”,依据“脏数据”所做的操作可能是不正确的。

1.3.2 不可重复读

比如在一个事务内多次读同一数据。在这个事务还没有结束时,另一个事务也访问该数据。那么,在第一个事务中的两次读数据之间,由于第二个事务的修改导致第一个事务两次读取的数据可能不太一样。这就发生了在一个事务内两次读到的数据是不一样的情况,因此称为不可重复读。

1.3.3 幻读

幻读与不可重复读类似。它发生在一个事务(T1)读取了几行数据,接着另一个并发事务(T2)插入了一些数据时。在随后的查询中,第一个事务(T1)就会发现多了一些原本不存在的记录,就好像发生了幻觉一样,所以称为幻读,他和不可重复读的主要区别在于一个每次读取是数据不一样,一个是读取的数量不一样。

1.4 四大隔离级别

为了解决并发事务存在的脏读、不可重复读、幻读等问题,数据库大叔设计了四种隔离级别。分别是读未提交,读已提交,可重复读,串行化(Serializable)

1.4.1 读未提交

读未提交隔离级别,只限制了两个数据不能同时修改,但是修改数据的时候,即使事务未提交,都是可以被别的事务读取到的,这级别的事务隔离有脏读、重复读、幻读的问题;

1.4.2 读已提交

读已提交隔离级别,当前事务只能读取到其他事务提交的数据,所以这种事务的隔离级别解决了脏读问题,但还是会存在重复读、幻读问题;

1.4 3 可重复读

可重复读隔离级别,限制了读取数据的时候,不可以进行修改,所以解决了重复读的问题,但是读取范围数据的时候,是可以插入数据,所以还会存在幻读问题;

1.4.4 串行化

事务最高的隔离级别,在该级别下,所有事务都是进行串行化顺序执行的。可以避免脏读、不可重复读与幻读所有并发问题。但是这种事务隔离级别下,事务执行很耗性能。

1.5 数据库是如何保证事务的隔离性的呢?

数据库是通过加锁,来实现事务的隔离性的。这就好像,如果你想一个人静静,不被别人打扰,你就可以在房门上加上一把锁。

加锁确实好使,可以保证隔离性。比如串行化隔离级别就是加锁实现的。但是频繁的加锁,导致读数据时,没办法修改,修改数据时,没办法读取,大大降低了数据库性能

那么,如何解决加锁后的性能问题的?

答案就是,MVCC多版本并发控制!它实现读取数据不用加锁,可以让读取数据同时修改。修改数据时同时可读取。

MVCC实现原理

主要依赖于记录中的三个隐藏字段、undolog,read view来实现的。

1、隐藏字段

每行记录,除了我们自定义的字段外,还有数据库隐式定义的DB_TRX_ID,DB_ROLL_PTR,DB_ROW_ID等字段:

  • DB_ROW_ID:6字节,隐藏的主键,如果数据表没有主键,那么innodb会自动生成一个6字节的row_id
  • ​DB_TRX_ID:6字节,最近修改事务id,记录创建这条记录或者最后一次修改该记录的事务id
  • DB_ROLL_PTR:7字节,回滚指针,用于配合undo日志,指向上一个旧版本

假设有一条数据如下:

2、undolog

2.1 概念
回滚日志,表示在进行insert,delete,update操作的时候产生的方便回滚的日志。

2.2 说明

  • 当进行insert操作的时候,产生的undolog,只在事务回滚的时候需要用到,并且在事务提交之后可以被立刻丢弃
  • 当进行update和delete操作的时候,产生的undolog,不仅仅在事务回滚的时候需要,在快照读的时候也需要,所以不能随便删除,只有在快照读或事务回滚不涉及该日志时,对应的日志才会被purge线程统一清除

当数据发生更新和删除操作的时候,实际只是设置了旧记录的deleted_bit,并不是将过时的记录删除,因为为了节省磁盘空间,innodb有专门的purge线程来清除deleted_bit为true的记录,如果某个记录的deleted_id为true,并且DB_TRX_ID相对于purge线程的read view 可见,那么这条记录就是可以被清除的。

2.3 undolog生成的记录链表
(1)假设有一个事务编号为1的事务向表中插入一条记录,那么此时行数据如下,主键id=1,事务id=1

(2)假设有第二个事务(编号为2)对该记录的name做出修改,改为lisi

底层操作:在事务2修改该行记录数据时
1、对该数据行加排他锁
2、把该行数据拷贝到undolog中,作为旧记录
3、修改该行name为lisi,并且修改事务id=2,回滚指针指向拷贝到undolog的副本记录中
4、提交事务,释放锁

(3)假设有第三个事务(编号为3)对该记录的age做了修改,改为32 

底层操作:在事务3修改该行记录数据时
1、对该数据行加排他锁
2、把该行数据拷贝到undolog中,作为旧记录,发现该行记录已经有undolog了,那么最新的旧数据作为链表的表头,插在该行记录的undolog最前面
3、修改该行age为32岁,并且修改事务id=3,回滚指针指向刚刚拷贝的undolog的副本记录
4、提交事务,释放锁

 上述的一系列图中,可以发现,不同事务或者相同事务的对同一记录的修改,会导致该记录的undolog生成一条记录版本链表,undolog的表头就是最新的旧记录,表尾就是最早的旧记录。

3、read view

Read View是事务进行快照读操作的时候生产的读视图,在该事务执行快照读的那一刻,系统会生成一个此刻的快照,记录并维护系统此刻活跃事务的id,用来做可见性判断的,也就是说当某个事务在执行快照读的时候,对该记录创建一个Read View的视图,把它当作条件去判断当前事务能够看到哪个版本的数据,有可能读取到的是最新的数据,也有可能读取到的是当前行记录的undolog中某个版本的数据

1)可见性算法

将要被修改的数据的最新记录中的DB_TRX_ID(当前事务id)取出来,与系统此刻其他活跃事务的id去对比,如果DB_TRX_ID跟Read View的属性做了比较,不符合可见性,那么就通过DB_ROLL_PTR回滚指针去取出undolog中的DB_TRX_ID做比较,即遍历链表中的DB_TRX_ID,直到找到满足条件的DB_TRX_ID,这个DB_TRX_ID所在的旧记录就是当前事务能看到的数据。

2)可见性规则

首先要知道Read View中的三个全局属性:

  • trx_list:一个数值列表,用来维护Read View生成时刻系统正活跃的事务ID(1,2,3)
  • up_limit_id:记录trx_list列表中事务ID最小的ID(1)
  • low_limit_id:Read View生成时,系统即将分配的下一个事务ID(4)

具体的比较规则如下:

  • 首先比较DB_TRX_ID < up_limit_id
    如果小于,则当前事务能看到DB_TRX_ID所在的记录
    如果大于等于,则进入下一个判断
  • 接下来判断DB_TRX_ID >= low_limit_id
    如果大于等于,则代表DB_TRX_ID所在的记录在Read View生成后才出现的,那么对于当前事务不可见
    如果小于,则进入下一步判断
  • 判断DB_TRX_ID是否在活跃事务中,trx_list包含DB_TRX_ID
    如果包含,则代表在Read View生成的时候,这个事务还是活跃状态,未commit的数据,当前事务也是看不到,如果不包含,则说明这个事务在Read View生成之前就已经开始commit,那么修改的结果是能够看见的。

流程图如下:

总结:两种情况可见

  • DB_TRX_ID < up_limit_id
  • DB_TRX_ID不在trx_list范围内,且小于low_limit_id

拓展 :在RC隔离级别下,是每个快照读都会生成并获取最新的Read View,而在RR隔离级别下,则是同一个事务中的第一个快照读才会创建Read View,之后的快照读获取的都是同一个Read View。

 


 

 

 

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

python核心编程(二)

python面向对象 一、基本理论二、 面向对象在python中实践2.1 如何去定义类2.2 通过类创建对象2.3 属性相关2.4 方法相关 三、python对象的生命周期,以及周期方法3.1 概念3.2 监听对象的生命周期 四、面向对象的三大特性4.1 封装4.2 继承4.2.1 概念4.2.1 目的4.2.2 分类4.2.3 t…

安装依赖报-gyp: No Xcode or CLT version detected!

错误 > node-gyp rebuild No receipt for com.apple.pkg.CLTools_Executables found at /. No receipt for com.apple.pkg.DeveloperToolsCLILeo found at /. No receipt for com.apple.pkg.DeveloperToolsCLI found at /. gyp: No Xcode or CLT version detected! gyp ERR!…

银行软件测试有哪些测试点?一般银行的软件测试工作流程有哪些?

银行测试行业前景广阔&#xff0c;随着金融科技的快速发展和银行业务的不断创新&#xff0c;银行对软件测试的需求也在持续增长。软件测试在确保银行系统软件的稳定性、安全性和可靠性方面起着至关重要的作用&#xff0c;因此&#xff0c;银行测试岗位一直受到广泛的关注和重视…

如何知道huggingface/modelscope的大模型的模型层名字

下载模型后&#xff0c;有个文件叫model.safetensors.index.json&#xff0c;里面有。 你下载的大模型位置在用户名/.cache/huggingface/hub/大模型名差不多这个路径。 或者直接print(parameters.name)&#xff0c;但是这样打出来特别多&#xff0c;很难看。差不多这样写&am…

高效掌控速卖通自养号测评:成本、步骤、技巧全方位掌握

在跨境电商的汹涌浪潮中&#xff0c;速卖通犹如一颗璀璨的领航星&#xff0c;引领着无数寻求海外拓展的企业和商家驶向国际市场的广阔海域。从最初的C2C模式起步&#xff0c;速卖通历经蜕变&#xff0c;如今已华丽转身成为B2C跨境电商领域的翘楚&#xff0c;承载着无数中国卖家…

【LeetCode刷题】滑动窗口解决问题:水果成篮、找到字符串中所有字母异位词

【LeetCode刷题】Day 9 题目1&#xff1a;904. 水果成篮思路分析&#xff1a;思路1&#xff1a;暴力枚举哈希表思路2&#xff1a;窗口滑动哈希表 题目2&#xff1a;438. 找到字符串中所有字母异位词思路分析&#xff1a;思路1&#xff1a;暴力枚举哈希表思路2&#xff1a;滑动窗…

2024年【焊工(高级)】报名考试及焊工(高级)操作证考试

题库来源&#xff1a;安全生产模拟考试一点通公众号小程序 焊工&#xff08;高级&#xff09;报名考试参考答案及焊工&#xff08;高级&#xff09;考试试题解析是安全生产模拟考试一点通题库老师及焊工&#xff08;高级&#xff09;操作证已考过的学员汇总&#xff0c;相对有…

短剧平台开发中的常见误区及避坑指南,别再走弯路

1. 误区一&#xff1a;只注重外观&#xff0c;忽视技术基础 在短剧平台开发中&#xff0c;一个常见的误区是过于注重产品的外观设计&#xff0c;而忽视了技术基础的重要性。团队往往会投入大量精力和资源来打造吸引人的UI和炫酷的特效&#xff0c;但忽略了系统架构、性能优化和…

外卖点餐二合一小程序源码系统 既能外卖配送也能到店点餐 附带完整的安装代码包以及搭建教程

系统概述 外卖点餐二合一小程序源码系统是一款专为餐饮行业打造的智能化解决方案。它不仅能够满足消费者线上点餐和外卖配送的需求&#xff0c;还能为餐厅提供高效的管理工具&#xff0c;实现线上线下一体化运营。该系统具有稳定的性能和可靠的安全保障&#xff0c;确保餐饮业…

垃圾回收机制及算法

文章目录 概要对象存活判断引用计数算法可达性分析算法对象是否存活各种引用 垃圾收集算法分代收集理论复制算法标记清除算法标记-整理算法 概要 垃圾收集&#xff08;Garbage Collection&#xff0c; 下文简称GC&#xff09;&#xff0c;其优缺点如下&#xff1a; 优点&#…

Java+IDEA+SpringBoot药物不良反应ADR智能监测系统源码 ADR智能化监测系统源码

JavaIDEASpringBoot药物不良反应ADR智能监测系统源码 ADR智能化监测系统源码 药物不良反应&#xff08;Adverse Drug Reaction&#xff0c;ADR&#xff09;是指在使用合格药品时&#xff0c;在正常的用法和用量下出现的与用药目的无关的有害反应。这些反应往往因药物种类、使用…

韩愈,文起八代之衰的儒学巨匠

&#x1f4a1; 如果想阅读最新的文章&#xff0c;或者有技术问题需要交流和沟通&#xff0c;可搜索并关注微信公众号“希望睿智”。 韩愈&#xff0c;字退之&#xff0c;生于唐代宗大历三年&#xff08;公元768年&#xff09;&#xff0c;卒于唐穆宗长庆四年&#xff08;公元82…

LangChain 0.2 - 对话式RAG

文章目录 一、项目说明二、设置1、引入依赖2、LangSmith 三、Chains1、添加聊天记录Contextualizing the question聊天记录状态管理 2、合并 四、Agents1、检索工具2、代理建造者3、合并 五、下一步 本文翻译整理自&#xff1a;Conversational RAG https://python.langchain.co…

spring suite gitlab使用手册

一、gitlab介绍 GitLab是一个功能丰富的开源代码管理平台&#xff0c;基于Git进行版本控制&#xff0c;并提供了一系列用于团队协作、项目管理、持续集成/持续部署&#xff08;CI/CD&#xff09;等工具。以下是关于GitLab的详细介绍&#xff1a; 基础信息&#xff1a; GitLab…

LiveGBS流媒体平台GB/T28181用户手册-云端录像:查看录像、列表视图、时间轴视图、下载、删除

LiveGBS流媒体平台GB/T28181用户手册-云端录像:查看录像、列表视图、时间轴视图、下载、删除 1、云端录像1.1、查看录像1.1.1、时间轴视图1.1.2、列表视图1.1.3、日期切换1.1.4、删除当天 1.2、录像计划1.2.1、录像计划列表1.2.2、编辑录像计划1.2.3、关联通道1.2.4、删除录像计…

每日练习之——背包问题

完全背包 题目描述 运行代码 #include<bits/stdc.h> #include<iostream> using namespace std; const int N1e33; int n,V; int v[N],w[N],dp[N]; int main(){cin>>n>>V; int t1;while(t--){for(int i1;i<n;i){cin>>v[i]>>w[i];}mems…

极简编程:一行JS代码获取全球各城市当前时间!

之前在一些国际化网站看到过&#xff0c;他们展示了当前北京、纽约和伦敦的时钟&#xff0c;在一次住店的时候&#xff0c;我也看到了类似的3个时钟&#xff0c;甚至更多&#xff0c;有的会展示东京时间。 让我觉得获取一些全球重点城市的当前时间&#xff0c;会是一个很常用的…

OrangePi Kunpeng Pro开发板初体验——家庭小型服务器

引言 在开源硬件的浪潮中&#xff0c;开发板作为创新的基石&#xff0c;正吸引着全球开发者的目光。它们不仅为技术爱好者提供了实验的平台&#xff0c;更为专业开发者带来了实现复杂项目的可能性。本文将深入剖析OrangePi Kunpeng Pro开发板&#xff0c;从开箱到实际应用&…

Bootstrap 3.x 版本基础引入指南

Bootstrap 是一款广受欢迎的前端框架&#xff0c;它简化了网页设计与开发流程&#xff0c;帮助开发者快速创建响应式布局和美观的网页界面。本文将向您介绍如何在项目中引入 Bootstrap 3.x 版本的基本步骤&#xff0c;包括 CSS 和 JavaScript 文件的引用&#xff0c;以及必要的…

PyTorch的数据处理

&#x1f4a5;今天看一下 PyTorch数据通常的处理方法~ 一般我们会将dataset用来封装自己的数据集&#xff0c;dataloader用于读取数据 Dataset格式说明 &#x1f4ac;dataset定义了这个数据集的总长度&#xff0c;以及会返回哪些参数&#xff0c;模板&#xff1a; from tor…