我的编程空间,编程开发者的网络收藏夹
学习永远不晚

MySQLMVVC多版本并发控制的实现详解

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

MySQLMVVC多版本并发控制的实现详解

一、概述

MVCC(Multiversion Concurrency Control),多版本并发控制。它和undo log中的版本链息息相关,MVVC通过数据行的多个版本来实现数据库的并发控制。

简单的说就是当前事务查询另一个事务正在更改的行(如果此时读取就会发生脏读),不用加锁等待,而是读取该数据的历史版本,降低响应时间。

MVVC是通过undo log和Read View两种技术实现的。

二、快照读与当前读

MVCC在MySQL InnoDB中的实现主要是为了提高数据库并发性能,用更好的方式去处理读-写冲突,做到即使有读写冲突时,也能做到不加锁,非阻塞并发读 ,而这个读指的就是快照读 , 而非当前读。当前读实际上是一种加锁的操作。

1.当前读

当前读读取的记录一定是最新的数据,读取时还要保证其他并发事务不能修改当前记录,会对读取的记录进行加锁。

加锁的读被称为当前读,还有数据的增删改都是要先读取数据的,这一读取过程也是当前读。

SELECT * FROM t LOCK IN SHARE MODE; # 共享锁
SELECT * FROM t FOR UPDATE; # 排他锁
UPDATE SET t..

2.快照读

快照读又叫一致性读,读取的是数据行的快照版本。在MySQL中,普通的select语句(不加for update或lock in share mode的select语句)默认就是使用的快照读,不加锁。

SELECT * FROM table WHERE ...

之所以这样,是因为快照读可以避免加锁操作,降低开销。

当事务的隔离级别是串行时,快照读就没有用了,会退化为当前读。

三、隔离级别与版本链复习

隔离级别:

在MySQL中默认的隔离级别就是可重复读RR,可以解决不可重复读问题,在MySQL中,特别的还额外支持解决幻读问题。

它是如何解决幻读问题的呢?有两种方式:

  • 使用间隙锁和临键锁解决,简而言之就是加锁,在此期间其他事务不能够插入数据
  • MVCC方式,无需加锁,消耗低(缺点是没有完全解决幻读问题)。

undo log版本链:

对应InnoDB来说,聚簇索引中的每个记录都包含了两个必要的隐藏字段:

  • trx_id:每次一个事务对某条聚簇索引记录进行改动时,都会把该事务的事务id赋值给trx_id隐藏列。
  • roll_pointer:回滚指针,每次修改数据时,都会把旧数据放入undo log日志中,新的数据指向该旧数据,做成一个版本链,该指针字段就称为回滚指针,通过该指针可以找到修改前的数据。

举例:

有一个id为8的事务创建了一条数据,那么该记录的示意图大概如下:

假设之后两个id分别为10、20的事务对这条记录进行update操作,流程如下:

事务10事务20
BEGIN; 
 BEGIN;
UPDATE student SET name='李四' WHERE id=1; 
UPDATE student SET name='王五' WHERE id=1; 
COMMIT; 
 UPDATE student SET name='赵六' WHERE id=1;
 UPDATE student SET name='钱七' WHERE id=1;
 COMMIT;

每次修改都会生成一个undo log日志,每个日志都相互链接,构成版本链,此时该条数据的示意图如下:

每个版本中还包含生成该版本时对应的事务id 。

四、Read View

有了undo log就可以读取到记录的历史版本,那么在什么情况下,读取哪个版本的记录呢?这就用到了Read View,它帮我们解决了行的可见性问题。

Read View就是当某个事务在使用MVVC机制进行快照读操作时产生的读视图。该视图是数据库当前所有活跃事务id(还未提交的事务)组成的列表的一个快照。

1.实现原理

四种隔离级别里,读未提交和串行化是不会使用MVVC的,因为读未提交直接读取某个数据的最新数据即可,串行化是通过加锁来读的。

读已提交和可重复读都必须保证读到的数据都是其他事务提交了的,所以,其他事务修改了数据但是还未提交,我们不能够访问该数据,但可以通过MVVC机制读取该记录的历史版本,核心问题就是需要判断版本链中的哪条历史版本是当前事务可见的,这也是ReadView要解决的问题。

Read View包含4个比较重要的内容:

  • creator_trx_id:创建这个Read View的事务id,Read View和事务是一一对应的。

只有事务对表中的记录做修改时才会为事务分配事务id,否则一个事务中只有读操作,该事务的id默认为0。

  • trx_ids:表示在生成Read View时当前系统中活跃的事务id列表。提交了的事务不在其中。
  • up_limit_id:活跃的事务中最小的事务id。
  • low_limit_id:表示生成Read View时系统应该分配给下一个事务的id值,同样也表示系统中最大的事务id值。

注意:low_limit_id并不是trx_ids中的最大值,事务id是递增分配的。比如,现在有id为1, 2,5这三个事务,之后id为5的事务提交了。那么一个新的读事务在生成ReadView时, trx_ids就包括1和2,up_limit_id的值就是1,low_limit_id的值就是6。

2.Read View规则

版本链

当某个事务有了Read View,访问某条记录时,需要按照下面的步骤判断该记录的哪个版本可见:

  • 如果该版本记录的trx_id和Read View的creator_trx_id相同,意味着该版本的记录是由当前事务修改的,因此该版本可以被当前事务访问
  • 如果该版本记录的trx_id小于Read View的up_limit_id,证明当前事务生成Read View时,此事务已经提交了,所以当前事务可以读取该版本。
  • 如果该版本的trx_id大于等于low_limit_id,证明生成该版本的事务在当前事务生成Read View之后才开启,所以该版本不可以被当前事务访问。
  • 如果被访问版本的trx_id属性值在ReadView的up_limit_id和low_limit_id之间,那就需要判断一下trx_id属性值是不是在trx_ids列表中,如果不在的话才能访问,否则不能访问。

3.整体流程

了解了这些概念之后,我们来看下当查询一条记录的时候,系统如何通过MVCC找到它:

  • 首先获取事务自己的版本号,也就是事务ID;
  • 获取 ReadView;
  • 查询得到的数据,然后与 ReadView 中的事务版本号进行比较;
  • 如果不符合 ReadView 规则,就需要从Undo Log中获取历史快照;
  • 最后返回符合规则的数据。

在隔离级别为读已提交时,一个事务中的每一次SELECT查询都会重新获取一次Read View,而可重复读是第一SELECT操作才会生成Read View,之后的查询操作复用这一个。

导致这两种的差距是因为:可重复读要保证一个事务中相同的SELECT读取的内容是相同的。

五、举例

1.READ

COMMITTED隔离级别下

现在有两个事务id分别为10、20的事务在执行:

-- id为10的事务
begin;
update t set name='李四' where id=1;
update t set name='王五' where id=1;
-- id为20的事务
更新其他行的数据

此刻,表中id为1的记录得到的版本链表如下所示:

此时新来一个事务执行如下操作:

begin;
select * from t where id=1;
-- 事务10、20未提交

查询到的结果为张三。

具体的过程如下:

  • 在执行select语句前,先生成一个Read View,Read View的creator_trx_id为0,trx_ids列表的内容是[10,20],up_limit_id为10,low_limit_id为21。
  • 查询name为王五的最新版本的记录,按规则进行对比,因为trx_id为10,10刚好是trx_ids中的记录,所以这条记录对当前事务不可见,根据回滚指针得到下一个版本
  • 下一个版本name为李四,也不行
  • 继续找到name为张三的版本,trx_id为8,8小于up_limit_id,所以该版本对当前事务可见,得到最终结果

接下来,再将id为10的事务进行commit提交。然后id为20的事务来更新记录:

begin;
-- id为20的事务
update t set name='赵六' where id=1;
update t set name='钱七' where id=1;

此时版本链更新为:

再到刚才使用READ COMMITTED隔离级别的事务中继续查找这个id 为1的记录,得到的结果为name=王五的那条记录。执行过程如下:

  • 生成Read View,Read View的creator_trx_id为0,trx_ids列表的内容是[20],up_limit_id为20,low_limit_id为21。
  • 因为前两个版本的记录trx_id为20,存在trx_ids中,所以跳过
  • 到第三条记录时,trx_id为10,小于20,可以读取,所以最终结果为王五

注意:READ COMMITTED,每次读取数据前都生成一个新的ReadView。

2.REPEATABLE READ隔离级别下

假如此时id为10的事务和id为20的事务正在修改,都未提交,修改内容和前面的一样,但是还未提交,此时当前事务做一个查询。

步骤为:

  • 生成Read View,Read View的creator_trx_id为0,trx_ids列表的内容是[10,20],up_limit_id为10,low_limit_id为21。
  • trx_id为10和20的都不满足要求
  • 最后查找到name为张三的历史版本的数据

此时,id为10的记录提交事务。

当前事务又需要select id为1的记录,步骤为:

  • 因为是可重复读,且第一次select已经生成过Read View了,所有会复用它,不重新生成。
  • 所以trx_id为10和20的记录依旧不符合规则,最终得到的数据还是张三,符合可重复读的规范

注意:REPEATABLE READ,每次读取都复用第一次生成的Read View

3.如何解决幻读

假设现在有一条数据,id为1

当前活跃的事务有10和20。

此时当前事务启动了,执行如下SQL语句:

begin;
select * from student where id>=1;

在开始前生成Read View,内容如下:creator_trx_id=0,trx_ids= [10,20] , up_limit_id=10, low_limit_id=21。

由于id大于等于1的数据只有一个,且该数据的trx_id为8,小于up_limit_id,所以可以读取到。

在这之后id为10的事务新增了一行数据,增加了id为2的数据,且提交了。

此时当前线程继续查找id>=1的数据,因为是可重复读,复用刚刚的Read View。

得到两行数据,但是因为id为2的数据trx_id为10,该值在Read View的trx_ids中存在,所以该记录对当前事务不可见,所以最后查询到的数据只有一条记录。

如果当前事务再插入id为2的数据就插不进去,所以说MVVC只解决了一半的幻读问题。

到此这篇关于MySQL MVVC多版本并发控制的实现详解的文章就介绍到这了,更多相关MySQL MVVC内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

MySQLMVVC多版本并发控制的实现详解

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

MySQL多版本并发控制MVCC详解

目录1.什么是MVCC2快照读与当前读2.1 快照读2.2当前读3.复习3.1 再谈隔离级别3.2 隐藏字段、Undo Log版本链4、MVCC实现原理之ReadView4.1什么是ReadView4.2 设计思路4.3 ReadView的
2022-07-25

Mysql InnoDB多版本并发控制MVCC详解

目录一丶为什么需要事务隔离级别1.实现事务隔离的方式:串行执行2.实现事务隔离的方式:可串行执行二丶并发事务执行的问题:脏写,脏读,不可重复读,幻读1.脏写2.脏读3.不可重复读4.幻读三丶隔离级别1.Read UnCommitted 读未
2022-11-29

mysql的MVCC多版本并发控制的实现

1 什么是MVCC MVCC全称是: Multiversion concurrency control,多版本并发控制,提供并发访问数据库时,对事务内读取的到的内存做处理,用来避免写操作堵塞读操作的并发问题。举个例子,程序员A正在读数据库中
2022-05-31

详解MySQL多版本并发控制机制(MVCC)源码

目录一、前言二、MVCC(多版本并发控制机制)2.1、Repeatable Read2.2、Read Commit2.3、MVCC的优势三、MVCC(实现机制)3.1、select运行栈3.2、read_view的创建过程3.3、行版本可见
2022-05-22

如何在PostgreSQL中实现多版本并发控制

在PostgreSQL中,多版本并发控制是通过使用MVCC(Multi-Version Concurrency Control)机制来实现的。MVCC使每个事务都能够访问数据库中的一个独立版本,并且可以避免数据丢失或不一致的情况。要实现多
如何在PostgreSQL中实现多版本并发控制
2024-04-09

怎么在mysql中实现MVCC多版本的并发控制

今天就跟大家聊聊有关怎么在mysql中实现MVCC多版本的并发控制,可能很多人都不太了解,为了让大家更加了解,小编给大家总结了以下内容,希望大家根据这篇文章可以有所收获。1 什么是MVCCMVCC全称是: Multiversion conc
2023-06-14

MySQL的多版本并发控制MVCC实现方法是什么

这篇文章主要讲解了“MySQL的多版本并发控制MVCC实现方法是什么”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“MySQL的多版本并发控制MVCC实现方法是什么”吧!什么是MVCCMVCC
2023-06-22

MySQL多版本并发控制——MVCC机制分析

原文:https://www.cnblogs.com/buptleida/p/14283943.html
MySQL多版本并发控制——MVCC机制分析
2019-04-27

Oracle中是否支持多版本并发控制

是的,Oracle数据库支持多版本并发控制(MVCC)。MVCC是一种并发控制机制,允许读取操作不会被写入操作所阻塞,同时也不会读取到正在被修改的数据。在Oracle数据库中,MVCC通过使用undo段和版本号来实现,确保在读取数据时不会受
Oracle中是否支持多版本并发控制
2024-04-09

《MySQL高级篇》十四、多版本并发控制

文章目录 1. 什么是MVCC2. 快照读与当前读2.1 快照读2.2 当前读 3. 复习3.1 再谈隔离级别3.2 隐藏字段、Undo Log版本链 4. MVCC实现原理之ReadView4.1 什么是ReadVie
2023-08-17

【Mysql】MVCC版本机制的多并发

🌇个人主页:平凡的小苏 📚学习格言:命运给你一个低的起点,是想看你精彩的翻盘,而不是让你自甘堕落,脚下的路虽然难走,但我还能走,比起向阳而生,我更想尝试逆风翻盘。 🛸Mysql专栏:Mys
2023-08-24

Mysql MVCC多版本并发控制的知识点有哪些

这篇文章主要介绍了Mysql MVCC多版本并发控制的知识点有哪些的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇Mysql MVCC多版本并发控制的知识点有哪些文章都会有所收获,下面我们一起来看看吧。1、MVC
2023-06-30

编程热搜

目录