如何理解MySql的MVCC机制

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;//拷贝原容器,长度为原容器+1Object[] 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.mzph.cn/web/38488.shtml

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

相关文章

【高中数学/三角函数】已知:x,y皆为实数,且4x^2+y^2+xy=1 求:2x+y的最大值

【问题】 已知&#xff1a;x,y皆为实数&#xff0c;且4x^2y^2xy1 求&#xff1a;2xy的最大值 【问题来源】 https://www.ixigua.com/7289764285772497448?logTag0d228277f3a8e049ab6d 【解答】 解&#xff1a; 由4x^2y^2xy1 可得 15/4*x^21/4*x^2xyy^21 得到(15开方/…

智能版面设计:指令跟随模型在自动布局规划中的应用

在广告行业一个吸引人的视觉布局能够显著提升信息的传播效果。但对于非专业设计师来说&#xff0c;创建既美观又功能性强的布局常常是一项挑战。他们往往缺乏必要的设计技能、审美训练或资源来快速实现创意构想。传统的设计软件和在线工具虽然提供了一些模板和指导&#xff0c;…

0702_ARM6

练习&#xff1a; 中断实验 main.c #include "key.h" int main() {//初始化rcc gpiohal_key_rcc_gpio_init();//初始化extihal_key_exti_init();//初始化gichal_key_gic_init();while(1){}return 0; }key.c #include "key.h"//GPIOF初始化 void hal_key_…

Linux的一些杂项函数总结

getopt_long 解析命令行。 参考&#xff1a; C语言linux getopt_long()函数&#xff08;命令行解析&#xff09;&#xff08;getopt、getopt_long_only&#xff09;&#xff08;短选项 -&#xff0c;长选项 --&#xff09;&#xff08;option结构体&#xff09;&#xff08;opt…

vue3-openlayers marker 光晕扩散(光环扩散)(postrender 事件和 render 方法)

本篇介绍一下使用 vue3-openlayers marker 光晕扩散&#xff08;光环扩散&#xff09;&#xff08;postrender 事件和 render 方法&#xff09; 1 需求 marker 光晕扩散&#xff08;光环扩散&#xff09; 2 分析 marker 光晕扩散&#xff08;光环扩散&#xff09;使用 post…

中级java每日一道面试题-2024年7月2日

题目&#xff1a; 请解释一下 Java 中的线程安全问题&#xff0c;并提供一些常见的解决方法。 答案&#xff1a; 线程安全问题是指在多线程环境下&#xff0c;多个线程同时访问共享资源时可能出现的数据不一致或错误的情况。这可能导致程序的不可预测性和错误的结果。 常见的…

徐州三线服务器租用的优势有哪些?

对于单线服务器与双线服务器来说&#xff0c;三线服务器是能够同时拥有电信、联通和移动三条线路的服务器&#xff0c;同时也被称为三线路由器或者是三线宽带路由器&#xff0c;有着三个独立的网卡和三个IP地址&#xff0c;使用户无论是通过哪些线路连接都能够进入服务器&#…

android.bp 静态库 依赖 动态库

在Android平台上&#xff0c;使用Android.bp文件来定义和构建Android静态库&#xff08;.so文件&#xff09;和动态库&#xff08;.so文件&#xff09;之间的依赖关系是很常见的。以下是一个简单的例子&#xff0c;展示了如何在Android.bp文件中定义一个静态库&#xff0c;它依…

SPI NAND、SD NAND和eMMC对比—MK米客方德

目录 1. 容量: 2.封装类型&#xff1a; 3.速度: 4.性能: 5.寿命: 6. 使用方式: 7. 其他优缺点: 8.常见应用场景: 1. 容量: SPI NAND通常提供从几百MB到几GB的存储容量。 SD NAND的容量覆盖范围比SPI NAND更广&#xff0c;从几GB到几十GB不等。 eMMC的容量范围更大&a…

代码随想录第41天|动态规划

322. 零钱兑换 dp[j] : 最小硬币数量, j 为金额(相当于背包空间)递推公式 : dp[j] min(dp[j - coins[i]] 1, dp[j])初始化: 需要一个最大值, 避免覆盖, dp[0] 0遍历顺序: 钱币有序无序不影响, 因为求解最小个数, 结果相同(先遍历物品后背包, 先背包后物品都可) class Solut…

【chatgpt】两层gcn提取最后一层节点输出特征,如何自定义简单数据集

文章目录 两层gcn&#xff0c;提取最后一层节点输出特征&#xff0c;10个节点&#xff0c;每个节点8个特征&#xff0c;连接关系随机生成&#xff08;无全连接层&#xff09;如何计算MSE 100个样本&#xff0c;并且使用批量大小为32进行训练第一个版本定义数据集出错&#xff0…

怎样在《语文世界》期刊上发表论文?

怎样在《语文世界》期刊上发表论文&#xff1f; 《语文世界》知网国家级 1.5-2版 2500字符左右 正常收25年4-6月版面 可加急24年内&#xff08;初中&#xff0c;高中&#xff0c;中职&#xff0c;高职&#xff0c;大学均可&#xff0c;操作周期2个月左右&#xff09; 《语文世…

【084】基于SpringBoot实现的家乡特色推荐系统

系统介绍 视频演示 点击查看演示视频 基于SpringBoot实现的家乡特色推荐系统主要采用SpringBootVue进行开发&#xff0c;系统整体分为管理员、用户两种角色&#xff0c;主要功能包括首页&#xff0c;个人中心&#xff0c;用户管理&#xff0c;文章分类管理&#xff0c;文章分…

C语言结构体深入解析【结构体嵌套结构体,结构体变量和指针,结构体和函数,计算结构体大小,结构体数组,结构体成员的访问,结构体与联合】

C语言结构体深入解析 目录 C语言结构体深入解析前言结构体的定义结构体在内存中的表示结构体变量初始化直接定义并初始化使用自己定义的结构体变量初始化新变量结构体数组初始化 结构体中嵌套结构体结构体成员访问点操作符(.)箭头操作符(->) 结构体变量和指针结构体指针定义…

TensorFlow代码逻辑 vs PyTorch代码逻辑

文章目录 一、TensorFlow&#xff08;一&#xff09;导入必要的库&#xff08;二&#xff09;加载MNIST数据集&#xff08;三&#xff09;数据预处理&#xff08;四&#xff09;构建神经网络模型&#xff08;五&#xff09;编译模型&#xff08;六&#xff09;训练模型&#xf…

@RequestMapping属性详解及案例演示

RequestMapping源码 Target({ElementType.TYPE, ElementType.METHOD}) Retention(RetentionPolicy.RUNTIME) Documented Mapping public interface RequestMapping {String name() default "";AliasFor("path")String[] value() default {};AliasFor(&quo…

智能写作与痕迹消除:AI在创意文案和论文去痕中的应用

作为一名AI爱好者&#xff0c;我积累了许多实用的AI生成工具。今天&#xff0c;我想分享一些我经常使用的工具&#xff0c;这些工具不仅能帮助提升工作效率&#xff0c;还能激发创意思维。 我们都知道&#xff0c;随着技术的进步&#xff0c;AI生成工具已经变得越来越智能&…

简单分享 for循环,从基础到高级

1. 基础篇&#xff1a;Hello, For Loop! 想象一下&#xff0c;你想给班上的每位同学发送“Hello!”&#xff0c;怎么办&#xff1f;那就是for循环啦&#xff0c; eg&#xff1a;首先有个名字的列表&#xff0c;for循环取出&#xff0c;分别打印 names ["Alice", …

Apache APISIX 介绍

Apache APISIX 是一个动态、实时、高性能的云原生API网关&#xff0c;属于Apache软件基金会旗下的项目。以下是对Apache APISIX的详细介绍&#xff1a; 一、基本概述 定义&#xff1a;Apache APISIX是一个提供丰富流量管理功能的云原生API网关。功能&#xff1a;包括负载均衡…

git出现Permission denied问题

Warning: Permanently added ‘icode.baidu.com,10.11.81.103’ (RSA) to the list of known hosts. Permission denied (baas,keyboard-interactive,publickey). fatal: Could not read from remote repository. Please make sure you have the correct access rights and the…