聊聊多版本并发控制(MVCC)

多版本并发控制(MVCC)

MVCC一直是数据库部分的高频面试题,这篇文章来聊聊MVCC是什么,以及一些底层原理的实现。

当前读和快照读:

  • 当前读:读取的是事务最新的版本,读取的过程中其他并发事务不能进行修改,需要对读取的记录进行加锁。
  • 快照读:不加任何锁的select语句就是快照读。假如在可重复读隔离级别下,事务A进行select先后两次读取,而事务B在两次读取过程中修改了数据并提交了事务,那么事务A读到的就不是最新版本的数据。如果想读到最新版本的数据,需要在读取的过程中加锁,如select ... lock in share mode.
    • 读已提交隔离级别下:每次select都是一次快照读,因为每次读都可能读取到的是其他事务已经提交的增删改操作
    • 可重复读隔离级别下:开启事务后第一次select才是快照读,因为其后的select读取不到其他事务提交的增删改操作
    • 串行化隔离级别下:每次select都是一次当前读,因为每次读取都会加锁

MVCC的概念:

  • MVCC即多版本并发控制,维护一个数据的多个版本,使得不同事务之间的读写操作没有冲突。
  • 什么是版本:一行记录修改前和修改后就是两个不同的版本。

MVCC的实现原理:

  • MVCC依靠三样东西来实现:隐藏字段undo logreadview
  • 创建一个表的时候InnoDB会给表加上三个隐藏字段****DB_TRX_IDDB_ROLL_PTRDB_ROLL_ID
    • DB_TRX_ID:最近一次修改这一行记录的事务的id。比如DB_TRX_ID = 4,表示最近一次修改这行 记录的事务是4。
    • DB_ROLL_PTR:回滚指针,指针指向这行记录的上一个版本,用于配合undo log回滚日志来找到这行记录的上一个版本(执行增删改之前的版本)
    • DB_ROLL_ID:隐藏主键。如果表没有指定主键的时候会自动生成。如果已经指定了主键,就不会生成。

请在此添加图片描述

  • undo log:在insert的时候,undo log只在回滚的时候需要,在事务提交后可以立即删除,不需要记录上一个版本该行的数据(因为上一版本该行不存在;在updatedelete的时候,不仅回滚的时候需要,多版本并发控制的时候也需要用来记录上一数据版本,用于多版本并发控制,因此事务提交后也不会立即删除。
    • undo log版本链

请在此添加图片描述

  • readview:每次事务执行快照读都有可能会生成readview。决定快照读读取的是undo log版本链中的哪一条历史记录。readview记录的是当前活跃中(未提交)的事务的id,包含以下四个字段:
    • m_ids:当前正在活跃中的事务的集合
    • min_trx_id:最小的活跃中的事务id
    • max_trx_id:不是当前正在活跃中的事务集合的最大id,而是预分配的事务id,即最大活跃中的事务id+1(因为事务id是自增的,因此加一)
    • creator_trx_id:readview创建者的事务id
    • 版本链数据的访问规则:trx_id:undo log记录的当前事务的id,即隐藏字段DB_TRX_ID,用这个id去匹配下面的规则,如果符合其中某一条件,说明当前版本是可以读取的;如果不符合条件,说明这个版本的数据不能读,就会顺着版本链去寻找更老的版本的数据
      • 如果trx_id = creator_trx_id:说明数据就是当前事务修改的,因此是可以读取到的
      • 如果trx_id < min_trx_id:说明当前事务不是活跃中的事务(已经提交),已提交的数据版本是可以读取到的
      • 如果trx_id > max_trx_id:说明当前事务是在readview生成后才开启的(?),因此不可以访问该版本的数据
      • 如果min_trx_id < trx_id <= max_trx_id且 trx_id不属于活跃中的事务的集合,说明该事务数据已经提交,已提交的数据版本是可以读取到的
      • readview的生成时机:不同隔离级别生成时机不同。如果是读已提交隔离级别,那么在事务中每次执行快照读都会生成readview;如果是可重复读隔离级别,那么只在事务第一次执行快照读的时候生成readview,后续会复用这个readview

MVCC演示:

  • 读已提交隔离级别:在这种隔离级别下,每一次快照读都会生成一个readview,在事务5中,第一次快照读会有三个活跃中的事务3、4、5;第二次快照读由于事务3已经提交,因此只有两个活跃中的事务4和5。
    • 第一次快照读,此时有三个活跃中的事务3、4、5;
      • 最近一次对id = 30这行记录进行修改的事务id是4,即trx_id = 4,均不符合版本链数据的访问规则,因此顺着版本链去寻找更老版本的数据,即trx_id = 3;
      • trx_id = 3,也均不符合版本链数据的访问规则,继续寻找trx_id = 2;
      • trx_id = 2时,符合第二条规则,trx_id(2) < min_trx_id(3),小于最小的正在活跃中的事务id,说明trx_id = 2这个事务已经提交了,结合读已提交隔离级别的宏观理解,并发事务是可以读取到其他事务已经提交的数据的,因此查询结果就是trx_id = 2对应的版本
    • 第二次快照读,此时有两个活跃中的事务4、5。
      • 最近一次对id = 30这行记录进行修改的事务id是4,即trx_id = 4,均不符合版本链数据的访问规则,因此顺着版本链去寻找更老版本的数据,即trx_id = 3;
      • trx_id = 3时,符合第二条规则,trx_id(3) < min_trx_id(4),小于最小的正在活跃中的事务id,说明trx_id = 3这个事务已经提交了,结合读已提交隔离级别的宏观理解,并发事务是可以读取到其他事务已经提交的数据的,因此查询结果就是trx_id = 3对应的版本

请在此添加图片描述

可重复读隔离级别:在这种隔离级别下,只在事务第一次执行快照读的时候生成readview,后续再读取的时候会复用这个readview。以下过程和读已提交隔离级别的过程相同,唯一的区别是读已提交隔离级别两次执行快照读都会生成新的readview,因而两次读取的结果不同;而可重复读隔离级别两次执行快照读的readview都相同,因而读取结果相同。上述过程就是不可重复读的底层原理。

  • 第一次快照读,此时有三个活跃中的事务3、4、5;
    • 最近一次对id = 30这行记录进行修改的事务id是4,即trx_id = 4,均不符合版本链数据的访问规则,因此顺着版本链去寻找更老版本的数据,即trx_id = 3;
    • trx_id = 3,也均不符合版本链数据的访问规则,继续寻找trx_id = 2;
    • trx_id = 2时,符合第二条规则,trx_id(2) < min_trx_id(3),小于最小的正在活跃中的事务id,说明trx_id = 2这个事务已经提交了,结合读已提交隔离级别的宏观理解,并发事务是可以读取到其他事务已经提交的数据的,因此查询结果就是trx_id = 2对应的版本
  • 第二次快照读复用第一次采用的readview,因此读取结果相同。

请在此添加图片描述

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

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

相关文章

适用于 Windows 的 6 个最佳视频转换器

视频转换器可以帮助您在设备上转换和播放不受支持的视频格式。它还可以方便地减小视频文件大小、以通用格式组织所有视频或与其他人共享文件以在不同设备上播放。 Windows 有大量视频转换器可供选择。虽然有些是免费的&#xff0c;但其他一些则提供迎合专业用户的高级功能。在…

【DETR系列目标检测算法代码精讲】01 DETR算法01 DETR算法框架和网络结构介绍

为什么要有DETR 总所周知&#xff0c;传统的目标检测算法非常依赖于anchor和nms等手工设计操作&#xff0c;非常费时费力&#xff0c;自然而然的就产生了取消这些操作的想法。但是我们首先需要思考的是&#xff0c;为什么我们需要anchor和nms&#xff1f; 因为我们是没有指定…

安卓玩机工具推荐----MTK芯片读写分区 备份分区 恢复分区 制作线刷包 从0开始 工具操作解析【三】

同类博文; 安卓玩机工具推荐----MTK芯片读写分区 备份分区 恢复分区 制作线刷包 工具操作解析 安卓玩机工具推荐----MTK芯片读写分区 备份分区 恢复分区 制作线刷包 工具操作解析【二】-CSDN博客 回顾以往 在以前的博文简单介绍了这款工具的rom制作全程。今天针对这款工具的…

【Java多线程】8——CompletableFuture

8 CompletableFuture ⭐⭐⭐⭐⭐⭐ Github主页&#x1f449;https://github.com/A-BigTree 笔记仓库&#x1f449;https://github.com/A-BigTree/tree-learning-notes 个人主页&#x1f449;https://www.abigtree.top ⭐⭐⭐⭐⭐⭐ 如果可以&#xff0c;麻烦各位看官顺手点个s…

【UI框架】——保姆式使用教程

&#x1f468;‍&#x1f4bb;个人主页&#xff1a;开发者-曼亿点 &#x1f468;‍&#x1f4bb; hallo 欢迎 点赞&#x1f44d; 收藏⭐ 留言&#x1f4dd; 加关注✅! &#x1f468;‍&#x1f4bb; 本文由 曼亿点 原创 &#x1f468;‍&#x1f4bb; 收录于专栏&#xff1a…

win11 环境配置 之 Jmeter(JDK17版本)

一、安装 JDK 1. 安装 jdk 截至当前最新时间&#xff1a; 2024.3.27 jdk最新的版本 是 官网下载地址&#xff1a; https://www.oracle.com/java/technologies/downloads/ 建议下载 jdk17 另存为到该电脑的 D 盘下&#xff0c;新建jdk文件夹 开始安装到 jdk 文件夹下 2. 配…

Java23种常见设计模式汇总

七大原则网站地址&#xff1a;设计模式7大原则&#xff0b;类图关系-CSDN博客 创建型设计模式&#xff1a;创建型设计模式合集-CSDN博客 七大结构型设计模式&#xff1a;7大结构型设计模式-CSDN博客 11种行为型设计模式&#xff1a; 11种行为型模式&#xff08;上&#xff0…

Oracle 19c 高可用部署实战系列之Data Guard理论与实战

课程介绍 Oracle Data Guard确保企业数据的高可用性、数据保护和灾难恢复。 Oracle Data Guard提供了一组全面的服务&#xff0c;用于创建、维护、管理和监视一个或多个备用数据库&#xff0c;使生产Oracle数据库能够在灾难和数据损坏中幸存下来。Oracle Data Guard将这些备用…

我于窗中窥月光,恰如仰头见“链表”(Java篇)

本篇会加入个人的所谓‘鱼式疯言’ ❤️❤️❤️鱼式疯言:❤️❤️❤️此疯言非彼疯言 而是理解过并总结出来通俗易懂的大白话, 小编会尽可能的在每个概念后插入鱼式疯言,帮助大家理解的. &#x1f92d;&#x1f92d;&#x1f92d;可能说的不是那么严谨.但小编初心是能让更多人…

java项目通用Dockerfile

创建Dockerfile文件&#xff0c;放到项目根目录下和pom.xml同级别 仅需修改为自己项目端口号即可&#xff0c;其他的无需改动 FROM openjdk:11.0.11-jre-slimCOPY target/*.jar .EXPOSE 8080ENTRYPOINT java -jar *.jar构建语句(注意末尾的点 . ) docker build -t container…

Android Studio Iguana | 2023.2.1 补丁 1

Android Studio Iguana | 2023.2.1 Canary 3 已修复的问题Android Gradle 插件 问题 295205663 将 AGP 从 8.0.2 更新到 8.1.0 后&#xff0c;任务“:app:mergeReleaseClasses”执行失败 问题 298008231 [Gradle 8.4][升级] 由于使用 kotlin gradle 插件中已废弃的功能&#…

C语言例1-3:设 int a; ,语句 for(a=0;a==0;a++); 和语句 for(a=0;a=0;a++); 执行的循环次数分别是

答案&#xff1a;1,0 代码如下&#xff1a; #include<stdio.h> int main(void) {int a;for(a0;a0;a){printf("1\n");} return 0; } 结果如下&#xff1a; 代码如下&#xff1a; #include<stdio.h> int main(void) {int a;for(a0;a0;a){printf("…

京东云8核16G服务器配置租用优惠价格1198元1年、4688元三年

京东云轻量云主机8核16G服务器租用优惠价格1198元1年、4688元三年&#xff0c;配置为8C16G-270G SSD系统盘-5M带宽-500G月流量&#xff0c;华北-北京地域。京东云8核16G服务器活动页面 yunfuwuqiba.com/go/jd 活动链接打开如下图&#xff1a; 京东云8核16G服务器优惠价格 京东云…

杰理芯片AC79——物联网远程点亮/关闭LED灯

杰理芯片的封装简直太香了&#xff08;比STM32香多了&#xff09;&#xff0c;SDK也封装得很好&#xff0c;对于我这种手残党简直不要太友好。赶紧学起来&#xff0c;快速实现你想要的功能吧&#xff01; 芯片选型 杰理AC79 资料文档 环境搭建以及点亮第一盏灯请访问&#x…

【一】DDR3基础知识与IMG IP

【一】DDR3基础知识与IMG IP 一、DDR3的基本知识 1、DDR3全称为第三代双倍速率同步动态随机存储器 特点&#xff1a;掉电无法保存数据&#xff0c;需要周期性的刷新&#xff1b;时钟上升沿和下降沿都在传输数据&#xff1b;突发传输&#xff0c;突发长度burtst length一般为…

Error: Cannot find module ‘@rollup/rollup-win32-x64-msvc‘

1.背景 新项目需要使用vite搭建一个v3项目,之前也弄过,但项目创建后却一直无法跑起来,大聪明的我一直没有注意到这个问题 2.解决步骤 方案1:删除node_modules和package-lock.json文件重新npm install下包,部分码农通过这个步骤可解决 方案2:node版本或者npm版本不对,或者没…

Vue3:快速上手路由器

本人在B站上关于vue3的尚硅谷的课程&#xff0c;以下是整理一些笔记。 一.路由器和路由的概念 在 Vue 3 中&#xff0c;路由&#xff08;Router&#xff09;和路由器&#xff08;Router&#xff09;是两个相关但不同的概念。 1. 路由&#xff08;Router&#xff09;&#xff…

LeetCode.2908. 元素和最小的山形三元组 I

题目 2908. 元素和最小的山形三元组 I 分析 首先&#xff0c;看到这道题&#xff0c;第一反应就是暴力方法&#xff0c;三层for循环&#xff0c;枚举每一种情况&#xff0c;代码如下 class Solution {public int minimumSum(int[] nums) {int min Integer.MAX_VALUE;for(i…

基于Springboot的学生选课系统(有报告)。Javaee项目,springboot项目。

演示视频&#xff1a; 基于Springboot的学生选课系统&#xff08;有报告&#xff09;。Javaee项目&#xff0c;springboot项目。 项目介绍&#xff1a; 采用M&#xff08;model&#xff09;V&#xff08;view&#xff09;C&#xff08;controller&#xff09;三层体系结构&…

线程池详解、核心参数、拒绝策略

什么是线程池 线程池是一种池化技术&#xff0c;它预先创建一组线程&#xff0c;用于执行异步任务。当有新任务到来时&#xff0c;线程池可以立即分配一个线程来处理&#xff0c;而不需要临时创建。这样可以减少因为频繁创建和销毁线程而导致的开销。 线程池的应用场景 高并…