您当前的位置:首页 > 电脑百科 > 数据库 > MYSQL

MySQL 中你必须要懂的 MVCC

时间:2020-06-28 09:27:49  来源:  作者:

前言

MySQL 是目前流行的开源数据库之一,各大公司都使用 MySQL 作为自家的关系型数据库,但是 MySQL 作为一个数据库而言,基本使用是非常简单的,只要会一点点建表语句(可以使用工具建表),一点点查询语句就可以使用 MySQL 来存储数据了。

这种没有灵魂的操作,对于很多初学者来说也许已经是家常便饭了。但是对于一些已经有开发经验的人来说,这是远远不够的。你必须要学习很多数据库相关的知识,而这一篇就是彻底来剖析 MySQL 中的 MVCC 是如何实现的。看完这篇文章,你就可以知道各种隔离级别之下,MVCC 的作用是什么?MVCC 在什么时候会使用?怎么使用?

示例表

CREATE TABLE `test`.`Untitled`  (
  `id` int(10) UNSIGNED NOT NULL AUTO_INCREMENT,
  `phone` char(11) NOT NULL,
  `name` varchar(255) NOT NULL,
  `age` int(3) NOT NULL,
  `country` varchar(255) NOT NULL,
  PRIMARY KEY (`id`) USING BTREE,
  UNIQUE INDEX `uk_phone`(`phone`) USING BTREE,
  INDEX `idx_name`(`name`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic;
复制代码
insert into person values (null, '1351111111', 'any', 20, '蜀');
insert into person values (null, '1351111112', 'bat', 21, '吴');
复制代码

id phone name age country 1 1351111111 any 20 蜀 2 1351111112 bat 21 吴

MVCC

MVCC 是无锁操作的一种实现方式,无锁就是没有锁。无锁能够大幅度提高数据库的并发性。它最基本的表现形式就是一致性非锁定读,通过 MVCC (多版本并发控制)来实现。MVCC 主要又是依靠 Read View 来实现的。

在数据库中的每一条记录实际都会存在三个隐藏列:

  • DB_TRX_ID:该列表示此记录的事务 ID
  • DB_ROLL_PTR:该列表示一个指向回滚段的指针,实际就是指向该记录的一个版本链
  • DB_ROW_ID:记录的 ID,如果有指定主键,那么该值就是主键。如果没有主键,那么就会使用定义的第一个唯一索引。如果没有唯一索引,那么就会默认生成一个值。
start transaction;
update person set age = 22 where id = 1;
update person set name = 'out' where id = 1;
commit;
复制代码

当执行完上面两条语句之后,但是还没有提交事务之前,它的版本链如下图所示:

MySQL 中你必须要懂的 MVCC

 

而 Read View 是用来判断每一个读取语句有资格读取版本链中的哪个记录。所以在在读取之前,都会生成一个 Read View。然后根据生成的 Read View 再去读取记录。

在事务中,只有执行插入、更新、删除操作时才会分配到一个事务 id。如果事务只是一个单纯的读取事务,那么它的事务 id 就是默认的 0。

Read View 的结构如下:

  • rw_trx_ids:表示在生成 Read View 时,当前活跃的读写事务数组。
  • min_trx_id:表示在生成 Read View 时,当前已提交的事务号 + 1,也就是在 rw_trx_ids 中的最小事务号。
  • max_trx_id:表示在生成 Read View 时,当前已分配的事务号 + 1,也就是将要分配给下一个事务的事务号。
  • curr_trx_id:创建 Read View 的当前事务 id。
MySQL 中你必须要懂的 MVCC

 

MySQL 会根据以下规则来判断版本链中的哪个版本(记录)是在事务中可见的:

  • trx_id < min_trx_id,那么该记录则在当前事务可见,因为修改该版本记录的事务在当前事务生成 Read View 之前就已经提交。
  • trx_id in (rw_trx_ids),那么该记录在当前事务不可见,因为需改该版本记录的事务在当前事务生成 Read View 之前还未提交。
  • trx_id > max_trx_id,那么该记录在当前事务不可见,因为修改该版本记录的事务在当前事务生成 Read View 之前还未开启。
  • trx_id = curr_trx_id,那么该记录在当前事务可见,因为修改该版本记录的事务就是当前事务。

例如:

MySQL 中你必须要懂的 MVCC

 

我们首先步骤 1 中开启了一个读取事务,因为它是一个只读事务,所以它的事务 id 为 0(以下简称事务 0)。紧接着我们在事务 0 中查询 id 为 1 的记录。此时,版本链如下:

MySQL 中你必须要懂的 MVCC

 

注意:跟红色表头连接在一起的记录都是在 B+ 树中的,而通过 roll_ptr 指针连接的记录都是存在于 undo log 中的。以下的所有版本链都是这种形式。

READ UNCOMMITTED

该隔离级别不会使用 MVCC。它只要执行 select,那么就会获取 B+ 树上最新的记录。而不管该记录的事务是否已经提交。

READ COMMITTED

在 READ COMMITTED 隔离级别下,会使用 MVCC。在开启一个读取事务之后,它会在每一个 select 操作之前都生成一个 Read View。

因为步骤 2 中的 select 读取时,没有活跃的事务,也就表明所有的事务都是已经提交了的。所以它能读取到第一条记录。

执行步骤 3, 开启一个新的事务,事务 id 为 101(以下检测事务 101)。

执行步骤 4,它修改了 id 为 1 的记录,此时版本链将会变为如下:

MySQL 中你必须要懂的 MVCC

 

执行步骤 5,事务 0 执行了一个 select 操作,事务 0 会生成一个 Read View。Read View 的值如下:

MySQL 中你必须要懂的 MVCC

 

我们根据上面对版本链中的记录可见性规则:

  1. 版本链中的第一条记录,它的 trx_id 不小于 min_trx_id,所以该记录不可见。
  2. 版本链中的第二条记录,它的 trx_id 小于 min_trx_id,所以该记录可见。

所以对于此次的查询,它能获得的记录就是:

MySQL 中你必须要懂的 MVCC

 

事务 101 在步骤 5 中执行了一个更新操作,执行步骤 6,提交该事务之后,版本链如下:

MySQL 中你必须要懂的 MVCC

 

执行步骤 7,我们在事务 0 中执行一次 select 查询,因为我们的隔离级别是 READ COMMITTED,所以此次查询也会生成一个 Read View。该 Read View 的值如下:

MySQL 中你必须要懂的 MVCC

 

然后根据版本链可见性规则:

  • 因为没有活跃的事务,可知所有事务都已经提交,所以 rw_trx_ids 为空。
  • 版本链第 1 条记录,它的 trx_id 小于 min_trx_id,所以此记录可见。

那么这次的查询可以得到的记录如下所示:

MySQL 中你必须要懂的 MVCC

 

在事务 0 执行完查询之后,我们又开启了一个事务 id 为 102 的新事务(以下简称事务 102),该事务也对 id 为 1的记录进行了更新。

步骤 9 中的查询自行分析。我们直接给出事务 102 执行完两条更新语句的最终版本链:

MySQL 中你必须要懂的 MVCC

 

执行步骤 11,根据版本链可见性规则,它能获取到的记录:

MySQL 中你必须要懂的 MVCC

 

REPEATABLE READ

实际上,REPEATABLE READ 与 READ COMMITTED 的区别只有在生成 Read View 的时机上。

READ COMMITTED 是在每次执行 select 操作时,都会生成一个新的 Read View。而 REPEATABLE READ 只会在第一次执行 select 操作时生成一个 Read View,直到该事务提交之前,所有的 select 操作都是使用第一次生成的 Read View。

我们重新执行一下表中的步骤。

首先,执行到步骤 2,事务 0 开启了事务之后,并执行一次 select 查询。此时会生成一个 Read View。该 Read View 的结构如下:

MySQL 中你必须要懂的 MVCC

 

生成的 Read View 将会一直使用,直到事务 0 提交。

所以,尽管后面的开启了两个事务,并且对记录进行修改,使得最终的版本链变为如下所示:

MySQL 中你必须要懂的 MVCC

 

但是事务 0 依然只能读取到最开始的那条记录,也就是:

MySQL 中你必须要懂的 MVCC

 

不管事务 0 在任何时候执行 select * from person where id = 1; 读取记录,那么它都只会使用第一次生成的 Read View 在版本链中选择可以读取的记录。

SERIALIZABLE

该隔离级别不会使用 MVCC。如果使用的是普通的 select 语句,它会在该语句后面加上 lock in share mode,变为一致性锁定读。假设一个事务读取一条记录,其他事务对该记录的更改都会被阻塞。假设一个事务在更改一条记录,其他事务对该记录的读取都会被阻塞。

在该隔离级别下,读写操作变为了串行操作。

总结

通过上面的文章,我们可以知道在 READ COMMITTED 和 REPEATABLE READ 隔离等级之下才会使用 MVCC。

但是 READ COMMITTED 和 REPEATABLE READ 使用 MVCC 的方式各不相同:

  • READ COMMITTED 是在每次执行 select 操作时都会生成一次 Read View。
  • REPEATABLE READ 只有在第一次执行 select 操作时才会生成 Read View,后续的 select 操作都将使用第一次生成的 Read View。

而 READ UNCOMMITTED 和 SERIALIZABLE 隔离级别不会使用 MVCC。

它们的读取操作也不相同:

  • READ UNCOMMITTED 每次执行 select 都会去读最新的记录。
  • SERIALIZABLE 每次执行 select 操作都会在该语句后面加上 lock in share mode,使 select 变为一致性锁定读,将读写进行串行化。


原文链接:https://juejin.im/post/5eeafc15e51d4573fa7d5824



Tags:MySQL MVCC   点击:()  评论:()
声明:本站部分内容及图片来自互联网,转载是出于传递更多信息之目的,内容观点仅代表作者本人,如有任何标注错误或版权侵犯请与我们联系(Email:2595517585@qq.com),我们将及时更正、删除,谢谢。
▌相关推荐
你是否对MySQL数据库中的事务已经有所了解?看下面这张图,按照1~6的顺序依次执行,在RR隔离级别下,事务A和事务B各自输出的num值是多少吗? 我们预先创建好这样一张表并初始化一条数...【详细内容】
2020-09-10  Tags: MySQL MVCC  点击:(117)  评论:(0)  加入收藏
前言MySQL 是目前流行的开源数据库之一,各大公司都使用 MySQL 作为自家的关系型数据库,但是 MySQL 作为一个数据库而言,基本使用是非常简单的,只要会一点点建表语句(可以使用工具...【详细内容】
2020-06-28  Tags: MySQL MVCC  点击:(57)  评论:(0)  加入收藏
什么是MVCCMulti-Version Concurrency Control 多版本并发控制,MVCC 是一种并发控制的方法,一般在数据库管理系统中,实现对数据库的并发访问;在编程语言中实现事务内存。MVCC有...【详细内容】
2019-09-25  Tags: MySQL MVCC  点击:(122)  评论:(0)  加入收藏
▌简易百科推荐
作者:雷文霆 爱可生华东交付服务部 DBA 成员,主要负责Mysql故障处理及相关技术支持。爱好看书,电影。座右铭,每一个不曾起舞的日子,都是对生命的辜负。 本文来源:原创投稿 *爱可生...【详细内容】
2021-12-24  爱可生    Tags:MySQL   点击:(7)  评论:(0)  加入收藏
生成间隙(gap)锁、临键(next-key)锁的前提条件 是在 RR 隔离级别下。有关Mysql记录锁、间隙(gap)锁、临键锁(next-key)锁的一些理论知识之前有写过,详细内容可以看这篇文章...【详细内容】
2021-12-14  python数据分析    Tags:MySQL记录锁   点击:(18)  评论:(0)  加入收藏
binlog 基本认识 MySQL的二进制日志可以说是MySQL最重要的日志了,它记录了所有的DDL和DML(除了数据查询语句)语句,以事件形式记录,还包含语句所执行的消耗的时间,MySQL的二...【详细内容】
2021-12-14  linux上的码农    Tags:mysql   点击:(13)  评论:(0)  加入收藏
为查询优化你的查询 大多数的MySQL服务器都开启了查询缓存。这是提高性最有效的方法之一,而且这是被MySQL的数据库引擎处理的。当有很多相同的查询被执行了多次的时候,这些查...【详细内容】
2021-12-09  元宇宙iwemeta    Tags:mysql   点击:(15)  评论:(0)  加入收藏
测试的目的和原因,公司有很多程序员,每个程序员对数据库和表结构都有自己的理解。而且每个程序员的理解往往是以效率考虑。既然都是为了效率考虑,那么我就来测试一下究竟哪种使...【详细内容】
2021-12-08  吴彬的分享    Tags:Mysql数据库   点击:(14)  评论:(0)  加入收藏
当你们考虑项目并发的时候,我在部署环境,当你们在纠结使用ArrayList还是LinkedArrayList的时候,我还是在部署环境。所以啊,技术不止境,我在部环境。今天这篇文章缕一下在同一台服...【详细内容】
2021-12-08  秃头码哥    Tags:MySQL数据库   点击:(17)  评论:(0)  加入收藏
对于数据分析来说,MySQL使用最多的是查询,比如对数据进行排序、分组、去重、汇总及字符串匹配等,如果查询的数据涉及多个表,还需要要对表进行连接,本文就来说说MySQL中常用的查询...【详细内容】
2021-12-06  笨鸟学数据分析    Tags:MySQL   点击:(21)  评论:(0)  加入收藏
在学习SQL语句之前,首先需要区分几个概念,我们常说的数据库是指数据库软件,例如MySQL、Oracle、SQL Server等,而本文提到的数据库是指数据库软件中的一个个用于存储数据的容器。...【详细内容】
2021-11-24  笨鸟学数据分析    Tags:SQL语句   点击:(23)  评论:(0)  加入收藏
概述以前参加过一个库存系统,由于其业务复杂性,搞了很多个应用来支撑。这样的话一份库存数据就有可能同时有多个应用来修改库存数据。比如说,有定时任务域xx.cron,和SystemA域...【详细内容】
2021-11-05  Java云海    Tags:分布式锁   点击:(31)  评论:(0)  加入收藏
MySQL的进阶查询 一、 按关键字排序 使用ORDERBY语句来实现排序排序可针对一个或多个字段ASC:升序,默认排序方式 【升序是从小到大】DESC:降序 【降序是从大到小】ORDER BY的...【详细内容】
2021-11-05  Java热点    Tags:SQL语句   点击:(28)  评论:(0)  加入收藏
最新更新
栏目热门
栏目头条