如何理解MySql的MVCC机制

news2024/7/7 18:03:28

MVCC是什么

MySQL的MVCC机制,全称为多版本并发控制(Multi-VersionConcurrency Control),是一种提高数据库并发性能的技术。MVCC的主要目的是在保证数据一致性的同时,提高数据库的并发性能。

它通过为每个读操作创建数据的快照来实现这一点,这样即使在数据被其他事务修改的同时,读操作也能够看到一致的数据视图。这种机制避免了同一个数据在不同事务之间的竞争,从而提高了系统的并发性能。

MVCC在MySQL中的实现主要是为了解决读写冲突问题,使得即使在有读写冲突的情况下,也能做到不加锁,非阻塞并发读。MVCC通过维护数据的不同版本来实现这一点,每个事务都可以看到适合自己版本的数据,而不会被其他事务的修改所影响。

MVCC适用范围

在MySQL中,MVCC只在读取已提交(Read Committed)和可重复读(Repeatable Read)两个事务级别下有效。底层通过Undolog日志中的版本链ReadView一致性视图来实现的。MVCC就是在多个事务同时存在时,SELECT语句找寻到具体是版本链上的哪个版本,然后在找到的版本上返回其中所记录的数据的过程。

当前读:总是读取当前最新的数据。

像select lock in share mode(共享锁), select for update ; update, insert ,delete(排他锁)这些操作都是一种当前读

快照读:像不加锁的select操作就是快照读,即不加锁的非阻塞读;快照读的前提是隔离级别不是串行级别串行级别下的快照读会退化成当前读;之所以出现快照读的情况,是基于提高并发性能的考虑,快照读的实现是基于多版本并发控制,即MVCC,可以认为MVCC是行锁的一个变种,但它在很多情况下,避免了加锁操作,降低了开销;既然是基于多版本,即快照读可能读到的并不一定是数据的最新版本,而有可能是之前的历史版本

update delete一定是当前读

表隐藏字段 

  • DB_ROW_ID:隐藏主键,MySQL的B+树索引特性要求每个表必须要有一个主键。如果没有设置的话,会自动寻找第一个不包含NULL的唯一索引列作为主键。如果还是找不到,就会在这个DB_ROW_ID上自动生成一个唯一值,以此来当作主键(该列和MVCC的关系不大);

  • DB_TRX_ID:最后一次事务ID,记录的是当前事务在做INSERT或UPDATE语句操作时的事务ID(DELETE语句被当做是UPDATE语句的特殊情况,后面会进行说明);

  • DB_ROLL_PTR:回滚指针,通过它可以将不同的版本串联起来,形成版本链。相当于链表的next指针。这个指针实际就是指向undolog的快照对应版本的数据。

MVCC的工作流程 

1. 事务开始时,获取一个唯一的事务ID。

2. 当进行读取操作时,数据库会创建一个Read View,其中包含了当前系统中活跃事务的信息。

3. 读取数据时,数据库会根据Read View中的信息来确定哪个版本的数据是可见的。

4. 如果当前版本的数据不可见,数据库会通过undo日志找到合适的历史版本。

MVCC与锁机制的比较

MVCC和锁机制都是并发控制的手段,但它们在不同的场景下有不同的应用。锁机制通过在数据上加锁来保证事务的隔离性,是一种悲观锁的实现。而MVCC通过维护数据的多个版本来实现非锁定读取,是一种乐观锁的实现。

无锁架构:COW思想

Copy-On-Write(COW,写时复制)是一种常见的并发编程思想。

Copy-On-Write基本思想是,当多个线程需要对共享数据进行修改时,不直接在原始数据上进行操作,而是先将原始数据复制一份(即写时复制),然后在副本上进行Write。

Copy-On-Write 通过操作写操作副本,引入局部无锁架构,解决并且处理之间的数据冲突,提高了并发性能。

Copy-On-Write的实现步骤如下:

  1. 读取数据:多个线程同时读取共享数据时,它们可以直接访问原始数据,而不需要复制。因为读取操作不会修改数据,所以可以安全地共享原始数据。

  2. 写入数据:当某个线程需要修改共享数据时,首先会将原始数据进行复制(即写时复制),然后在副本上进行修改。这样做的好处是,其他线程仍然可以继续读取原始数据,不受写入线程的影响。

  3. 更新引用:写入线程完成修改后,会更新共享数据的引用,使得其他线程后续访问时可以获取到最新的数据副本。

Copy-On-Write的优点包括:

  • 线程安全:通过复制数据副本并在副本上进行修改,避免了多线程并发修改原始数据时的数据冲突问题,从而提高了线程安全性。

  • 减少锁竞争:由于读取操作不需要加锁,所以可以减少锁竞争,提高了并发性能。

  • 节省内存:只有在有写入操作时才会进行数据复制,而读取操作可以共享原始数据,因此可以节省内存空间。

然而,Copy-On-Write也有一些缺点,主要是由于数据复制和更新引用所带来的额外开销,可能会导致内存和性能方面的消耗增加。因此,适用场景需要根据具体情况进行评估和选择。

COW思想写操作之间是要互斥的,并且每次写操作都会有一次copy,所以只适合读大于写的情况。所以,COW思想 专门用于优化读的次数远大于写次数的场景。比如,Java的 并发容器CopyOnWriteArrayList。

Java中的CopyOnWriteArrayList

CopyOnWriteArrayList 是jdk1.5以后并发包中提供的一种并发容器,写操作通过创建底层数组的新副本来实现,是一种读写分离的并发策略,我们也成为“写时复制容器”。

public boolean add(E e) {
   //加锁,对写操作保证线程安全
   final ReentrantLock lock = this.lock;
   lock.lock();
   try {
       Object[] elements = getArray();
       int len = elements.length;
       //拷贝原容器,长度为原容器+1
       Object[] newElements = Arrays.copyOf(elements, len + 1);
       //在新副本执行添加操作
       newElements[len] = e;
       //底层数组指向新的数组
       setArray(newElements);
       return true;
   } finally {
       lock.unlock();
   }
}

CopyOnWriteArrayList底层实现添加的原理是先copy出一个容器(可以简称副本),再往新的容器里添加这个新的数据,最后把新的容器的引用地址赋值给了之前那个旧的的容器地址,但是在添加这个数据的期间,其他线程如果要去读取数据,仍然是读取到旧的容器里的数据。

MVCC核心ReadView

先来思考如下的问题:

如果T1事务要查询id=1的一条行数据,此时这条行数据正在被T2事务修改,那也就代表着这条数据可能存在多个旧版本数据,T1事务在查询时,应该读这条数据的哪个版本呢?

此时就需要用到ReadView,用它来做多版本的并发控制,根据查询的时机,来选择一个当前事务可见的旧版本数据读取。

什么是ReadView呢? 

当一个事务在尝试读取一条数据时,MVCC基于当前MySQL的运行状态生成的快照,也被称之为读视图,即ReadView,在这个快照中记录着当前所有活跃事务的ID(活跃事务是指还在执行的事务,即未结束(提交/回滚)的事务)。

ReadView是事务在进行快照读的时候生成的记录快照, 可以帮助我们解决可见性问题的。

ReadView的核心属性

当一个事务启动后,首次执行select操作时,MVCC就会生成一个数据库当前的ReadView

通常而言,一个事务与一个ReadView属于一对一的关系(不同隔离级别下也会存在细微差异),ReadView一般包含4个核心属性:

我们假设目前数据库中共有T1~T6这6个事务,T1、T2、T4、T6还在执行,T3已经回滚,T5已经提交,

此时当有一条查询语句执行时,就会利用MVCC机制生成一个ReadView,由于在MySQL中单纯由一条select语句组成的事务并不会分配事务ID,因此默认为0,所以目前这个ReadView的信息如下:

ReadView的读取规则
 

访问某条记录的时候如何判断该记录是否可见,具体规则如下:

  • 如果被访问版本的 事务ID = creator_trx_id,那么表示当前事务访问的是自己修改过的记录,那么该版本对当前事务可见;

  • 如果被访问版本的 事务ID < up_limit_id,那么表示生成该版本的事务在当前事务生成 ReadView 前已经提交,所以该版本可以被当前事务访问。

  • 如果被访问版本的 事务ID > low_limit_id 值,那么表示生成该版本的事务在当前事务生成 ReadView 后才开启,所以该版本不可以被当前事务访问。

  • 如果被访问版本的 事务ID在 up_limit_id和m_low_limit_id之间,那就需要判断一下版本的事务ID是不是在 trx_ids 列表中,如果在,说明创建 ReadView 时生成该版本的事务还是活跃的,该版本不可以被访问;

  • 如果不在,说明创建 ReadView 时生成该版本的事务已经被提交,该版本可以被访问。

上面这种图,网上有上万篇文章, 都是抄来抄去, 没有一篇文章做了总结和简化。

关于这个对比规则,由于逻辑复杂,导致尽管大家看了那些文章,甚至看了很多视频,还是不能理解透彻, 迷迷糊糊的,面试的时候 说不清楚,也很容易忘了。

尼恩团队看不下去,用咱们的雄厚技术实力(洪荒之力), 给大家来总结和简化。

具体如下:

 

 

 

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

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

相关文章

基于若依(ruoyi-vue)的周报管理系统

喂wangyinlon 填报人页面 审批人 审批不通过,填报人需要重新填写.

【漏洞复现】D-Link NAS 未授权RCE漏洞(CVE-2024-3273)

0x01 产品简介 D-Link 网络存储 (NAS)是中国友讯&#xff08;D-link&#xff09;公司的一款统一服务路由器。 0x02 漏洞概述 D-Link NAS nas_sharing.cgi接口存在命令执行漏洞&#xff0c;该漏洞存在于“/cgi-bin/nas_sharing.cgi”脚本中&#xff0c;影响其 HTTP GET 请求处…

Flink实现准确和高效流处理的关键问题

时间相关: Watermark 水位线 水位线是插入到数据流中的一个标记,可以认为是一个特殊的数据。水位线主要的内容是一个时间戳,用来表示当前事件时间的进展。水位线是基于数据的时间戳生成的。水位线的时间戳必须单调递增,以确保任务的事件时间时钟一直向前推进,进展。水位线…

使用Arduino和超声波传感器测量声速

使用Arduino和超声波传感器测量声速 Step 1: 硬件 Arduino Uno单片机超声波传感器&#xff08;HC-SR04&#xff09;标尺跳线&#xff08;母/公&#xff09;计算器 Step 2: Arduino Uno 微控制器 The Arduino Uno is a credit card size microcontroller board. Arduino Uno是…

信息学奥赛初赛天天练-42-CSP-J2020基础题-变量地址、编译器、逻辑运算、逻辑与运算、逻辑或运算、冒泡排序、递归应用

PDF文档公众号回复关键字:20240702 2020 CSP-J 选择题 单项选择题&#xff08;共15题&#xff0c;每题2分&#xff0c;共计30分&#xff1a;每题有且仅有一个正确选项&#xff09; 1.在内存储器中每个存储单元都被赋予一个唯一的序号&#xff0c;称为&#xff08; &#xff0…

JavaScript中的Array(数组)对象

目录 一、Array数组对象 1、介绍 2、创建数组对象并赋值 3、访问数组元素 二、Array对象属性 1、constructor属性 2、length属性 3、prototype属性 三、Array对象的常用方法 1、isArray() 2、concat() 3、pop() 4、shift() 5、push() 6、unshift() 7、reverse(…

VQA视觉问答系统

这是一个典型的多模态问题,融合了CV与NLP的技术,计算机需要同时学会理解图像和文字。 Joint embedding 首先,图像和问题分别由CNN和RNN进行第一次编码得到各自的特征,随后共同输入到另一个编码器中得到joint embedding,最后通过解码器输出答案。 值得注意的是,有的工作…

我与C++的爱恋:list的使用

​ ​ &#x1f525;个人主页&#xff1a;guoguoqiang. &#x1f525;专栏&#xff1a;我与C的爱恋 一、list介绍 1.list是可以在常数范围内在任意位置进行插入和删除的序列式容器&#xff0c;并且该容器可以前后双向迭代 2.list的底层是双向链表结构&#xff0c;双向链表中…

python: create Envircomnet in Visual Studio Code 创建虚拟机

先配置python开发环境 1.在搜索栏输入“>" 或是用快捷组合键ctrlshiftP键 就会显示”>",再输入"python:" 选择已经安装好的python的版本,选定至当前项目中&#xff0c;都是按回车 就可以看到创建了一个虚拟机的默认的文件夹名".venv" 2 te…

KUKA仿真教学8:设备保养屏蔽

目录 一、屏蔽步骤 一、屏蔽步骤

ghost恢复?电脑文件恢复如何操作?电脑数据恢复工具!5款!

在数字化时代&#xff0c;电脑数据的价值日益凸显。然而&#xff0c;数据丢失、误删、系统崩溃等问题时有发生&#xff0c;给个人和企业带来巨大损失。本文将为您详细介绍Ghost恢复方法&#xff0c;同时推荐五款高效的电脑数据恢复工具&#xff0c;助您轻松应对数据丢失的困扰。…

Node.js学习(一)

Node.js安装与入门案例&#xff1a; 需求&#xff1a;点击按钮&#xff0c;请求本地目录指定文件的内容&#xff0c;并显示在页面上 刚入门肯定想着直接写相对路径请求指定路径数据就行了&#xff0c;可是会发现不行。 网页运行在浏览器端&#xff0c;通常后续要发布&#xf…

全面了解机器学习

目录 一、基本认识 1. 介绍 2. 机器学习位置 二、机器学习的类型 1. 监督学习 2. 无监督学习 3. 强化学习 三、机器学习术语 1. 训练样本 2. 训练 3. 特征 4. 目标 5. 损失函数 四、机器学习流程 五、机器学习算法 1. 分类算法 2. 聚类算法 3. 关联分析 4. …

高通骁龙(Qualcomm Snapdragon)CDSP HVX HTP 芯片简介与开发入门

1. Hexagon DSP/HVX/HTP 硬件演进 说到高通骁龙芯片大家应该不会陌生&#xff0c;其作为最为广泛的移动处理器之一&#xff0c;几乎每一个品牌的智能手机都会使用高通骁龙的处理器。 高通提供了一系列骁龙芯片解决方案。根据性能强弱分为了5个产品系列&#xff1a;从最高端的…

verilog实现PID控制

1 原理讲解 距离上一次说PID算法的事情过去蛮久了&#xff0c;今天又重新看了看PID的代码&#xff0c;其实还是存在一些不合理的地方。 整理归纳了一下原理&#xff0c;位置式和增量式的变化。 2 工程实现 timescale 1ns / 1psmodule pid_controller(input clk,input r…

MySQL——事务ACID原则、脏读、不可重复读、幻读

什么是事务 要么都成功&#xff0c;要么都失败 一一一一一一一 1. SQL执行&#xff1a;A给B转账 A 1000 ---->200 B 200 2. SQL执行&#xff1a;B收到A的钱 A 800 B 400 一一一一一一一 将一组SQL放在一个批次中去执行~ 事务原则&#xff1a;ACI…

从零搭建Prometheus到Grafana告警推送

目录 一、Prometheus源码安装和动态更新配置 二、Prometheus操作面板和常见配置 三、Prometheus常用监控组件exporter配置 3.1 exporter是什么 3.2 有哪些exporter 3.3 exporter怎么用 3.4 实战 node_exporter ​3.5 其它exporter都怎么用 四、Promethus整合新版Sprin…

线程状态转换总结

1. NEW -> RUNNABLE 创建线程后是 NEW 状态&#xff08;只是 Java 层面新建的&#xff0c;还没有关联到操作系统实际的线程上&#xff09;&#xff0c;调用线程的 start() 方法会将 Java 线程和操作系统的线程关联起来&#xff0c;进入 RUNNABLE 状态 2. RUNNABLE <->…

入门PHP就来我这(纯干货)05

~~~~ 有胆量你就来跟着路老师卷起来&#xff01; -- 纯干货&#xff0c;技术知识分享 ~~~~ 路老师给大家分享PHP语言的知识了&#xff0c;旨在想让大家入门PHP&#xff0c;并深入了解PHP语言。 1 数组及创建 数组&#xff0c;顾名思义&#xff0c;本质上就是一系列数据的组合…

【Linux进程通信】使用匿名管道制作一个简单的进程池

进程池是什么呢&#xff1f;我们可以类比内存池的概念来理解进程池。 内存池 内存池是在真正使用内存之前&#xff0c;先申请分配一定数量的、大小相等(一般情况下)的内存块留作备用。当有新的内存需求时&#xff0c;就从内存池中分出一部分内存块&#xff0c;若内存块不够再继…