(三) Mysql 之MVCC
mvcc介绍
MVCC是数据库提供并发访问控制的一种技术。其核心理念是数据快照,不同的事务访问不同版本的数据快照,从而实现不同的事务隔离级别。虽然是说具有多个版本的数据快照,但这并不意味着数据库必须拷贝数据,保存多份数据文件,这样会浪费大量的存储空间。mysql的InnoDB通过事务的undo日志巧妙地实现了多版本的数据快照。与基于锁的并发控制 Lock-Based Concurrency Control (LBCC)相比,MVCC最大的好处:读不加锁,读写不冲突。
InnoDB的MVCC是通过在每行记录后面保存两个隐藏的列来实现的。这两个列,一个保存了行的事务ID,一个保存了行的回滚指针。每开始一个新的事务,都会自动递增产生一个新的事务id。
MVCC只在REPEATABLE READ和READ COMMITIED两个隔离级别下工作。其他两个隔离级别都和MVCC不兼容 ,因为READ UNCOMMITIED总是读取最新的数据行,而不是符合当前事务版本的数据行。而SERIALIZABLE则会对所有读取的行都加锁。
MVCC 在mysql 中的实现依赖的是undo log与read view。
undo log
为了更好的支持并发,InnoDB的多版本一致性读是采用了基于回滚段的的方式。另外,对于更新和删除操作,InnoDB并不是真正的删除原来的记录,而是设置记录的delete mark为1。因此为了解决数据Page和Undo Log膨胀的问题,需要引入purge机制进行回收。Undo log保存了记录修改前的镜像。在InnoDB存储引擎中,undo log分为:insert undo log 与 update undo log。
insert undo log是指在insert操作中产生的undo log。由于insert操作的记录,只是对本事务可见,其他事务不可见,所以undo log可以在事务提交后直接删除,而不需要purge。
update undo log是指在delete和update操作中产生的undo log。该undo log会被后续用于MVCC当中,因此不能提交的时候删除。提交后会放入undo log的链表,等待purge线程进行最后的删除。
如下图所示(第一次修改):
当事务2使用UPDATE语句修改该行数据时,会首先使用排他锁锁定该行,将该行当前的值复制到undo log中,然后再真正地修改当前行的值,最后填写事务ID,使用回滚指针指向undo log中修改前的行。
ReadView
对于使用 READ UNCOMMITTED 隔离级别的事务来说,直接读取记录的最新版本就好了。对于使用SERIALIZABLE 隔离级别的事务来说,使用加锁的方式来访问记录。对于使用 READ COMMITTED 和REPEATABLE READ 隔离级别的事务来说,就需要用到我们上边所说的 版本链 了。核心问题就是需要判断一下版本链中的哪个版本是当前事务可见的。所以设计 InnoDB 的设计者提出了一个ReadView的概念,这个 ReadView 中主要包含当前系统中还有哪些活跃的读写事务,把它们的事务id放到一个列表中,我们把这个列表命名为m_ids,并确定三个变量的值:
m_up_limit_id:m_ids事务列表中的最小事务id,如果当前列表为空那么就等于m_low_limit_id。事务id的下限。
m_low_limit_id:系统中将要产生的下一个事务id的值。事务id的上限。
m_creator_trx_id:当前事务id,m_ids中不包含当前事务id
这样在访问某条记录时,只需要按照下边的步骤判断记录的某个版本(版本链中的版本)是否可见:
1)如果被访问版本的 trx_id 属性值小于 m_up_limit_id ,表明生成该版本的事务在生成 ReadView前已经提交,所以该版本可以被当前事务访问。
2)如果被访问版本的 trx_id 属性值等于 m_creator_trx_id 既当前事务id,可以被访问。
3)如果被访问版本的 trx_id 属性值大于等于 m_low_limit_id ,在生成 ReadView 后才生成,所以该版本不可以被当前事务访问。
4)如果被访问版本的 trx_id 属性值在 m_up_limit_id 和 m_low_limit_id 之间,那就需要判断一下 trx_id 属性值是不是在 m_ids 列表中。
如果在,说明创建 ReadView 时生成该版本的事务还是活跃的,该版本不可以被访问;
如果不在,说明创建 ReadView 时生成该版本的事务已经被提交,该版本可以被访问
在 MySQL 中, READ COMMITTED 和 REPEATABLE READ 隔离级别的的一个非常大的区别就是它们生成ReadView 的时机不同,如下。
1.READ COMMITTED
每次读取数据前都生成一个ReadView
数据库中的记录是id为1,c为刘备,该行记录的版本是80
# Transaction 100
BEGIN;
UPDATE t SET c = '关羽' WHERE id = 1;
UPDATE t SET c = '张飞' WHERE id = 1;
select c from t where id =1时
在执行SELECT语句时会先生成一个 ReadView,ReadView 的 m_ids 列表的内容就是 [100]
然后从版本链中挑选可见的记录,最新版本的列 c 的内容是 '张飞' ,该版本的trx_id值为100,
在 m_ids 列表内,所以不符合可见性要求,根据 roll_pointer 跳到下一个版本。
下一个版本的列 c 的内容是 '关羽' ,该版本的 trx_id 值也为 100 ,也在m_ids 列表内,所以也
不符合要求,继续跳到下一个版本。
下一个版本的列c的内容是'刘备',该版本的trx_id值为80,小于m_ids列表中最小的事务id 100,
所以这个版本是符合要求的,最后返回给用户的版本就是这条列c为'刘备'的记录。
# Transaction 200
BEGIN;
UPDATE t SET c = '赵云' WHERE id = 1;
UPDATE t SET c = '诸葛亮' WHERE id = 1;
执行如下操作:
select c from t where id =1时
在执行SELECT语句时会先生成一个 ReadView,ReadView 的 m_ids 列表的内容就是 [100,200],查找的结果仍然为刘备
此时可以看出,Transaction 100与200没有提交时,查询的结果仍然是刘备的,这就达到了RC隔离级别下的mvcc控制的效果
Transaction 100 事务提交
select c from t where id =1时
在执行SELECT语句时会重新生成一个 ReadView,ReadView 的 m_ids 列表的内容是 [200],查找的结果为张飞。事务1提交了,才查询到了最新的记录。
2.READ REPEATABLE
在事务开始后第一次读取数据时生成一个ReadVie
数据库中的记录是id为1,c为刘备,该行记录的版本是80
# Transaction 100
BEGIN;
UPDATE t SET c = '关羽' WHERE id = 1;
UPDATE t SET c = '张飞' WHERE id = 1;
select c from t where id =1时
在执行SELECT语句时会先生成一个 ReadView,ReadView 的m_ids列表的内容是 [100]
然后从版本链中挑选可见的记录,最新版本的列c的内容是'张飞',该版本的trx_id值为100,
在m_ids列表内,所以不符合可见性要求,根据 roll_pointer 跳到下一个版本。
下一个版本的列c的内容是'关羽' ,该版本的trx_id值也为100,也在m_ids 列表内,所以也
不符合要求,继续跳到下一个版本。
下一个版本的列c的内容是'刘备',该版本的trx_id值为80,小于m_ids列表中最小的事务id 100,
所以这个版本是符合要求的,最后返回给用户的版本就是这条列c为'刘备'的记录。
# Transaction 200
BEGIN;
UPDATE t SET c = '赵云' WHERE id = 1;
UPDATE t SET c = '诸葛亮' WHERE id = 1;
执行如下操作:
select c from t where id =1时
在执行SELECT语句时会第一次产生的ReadView 的 m_ids列表的内容就是[100],查找的结果仍然为刘备
Transaction 100 事务提交,
select c from t where id =1时
之前的ReadView的m_ids 列表的内容仍然是[100],查找的结果仍然为刘备,
这就可以看出,Transaction 100第一次查询时,在READ REPEATABLE隔离级别下,产生的ReadView的m_ids列表的内容是[100],尽管
之后Transaction 100 事务提交了,但是ReadView的m_ids列表没变,所以查询的结果仍然为刘备,达到了可重复读的效果。
每次读取数据前都生成一个ReadView
(三) Mysql 之MVCC的更多相关文章
- java面试一日一题:讲对mysql的MVCC的理解
问题:请讲下对mysql中MVCC的理解 分析:这个问题要回答的是对MVCC的理解,以及MVCC解决了什么问题这几个方面入手. 回答要点: 主要从以下几点去考虑, 1.什么是MVCC? 2.MVCC用 ...
- mysql的mvcc(多版本并发控制)
mysql的mvcc(多版本并发控制) 我们知道,mysql的innodb采用的是行锁,而且采用了多版本并发控制来提高读操作的性能. 什么是多版本并发控制呢 ?其实就是在每一行记录的后面增加两个隐藏列 ...
- {MySQL数据库初识}一 数据库概述 二 MySQL介绍 三 MySQL的下载安装、简单应用及目录介绍 四 root用户密码设置及忘记密码的解决方案 五 修改字符集编码 六 初识sql语句
MySQL数据库初识 MySQL数据库 本节目录 一 数据库概述 二 MySQL介绍 三 MySQL的下载安装.简单应用及目录介绍 四 root用户密码设置及忘记密码的解决方案 五 修改字符集编码 六 ...
- 【数据库】悲观锁与乐观锁与MySQL的MVCC实现简述
悲观锁 悲观锁,就是一种悲观心态的锁,每次访问数据时都会锁定数据: 乐观锁 乐观锁,就是一种乐观心态的锁,每次访问数据时并不锁定数据,期待数据并没作修改,如果数据没被修改则作具体的业务 应用程序上使用 ...
- MySQL InnoDB MVCC
MySQL 原理篇 MySQL 索引机制 MySQL 体系结构及存储引擎 MySQL 语句执行过程详解 MySQL 执行计划详解 MySQL InnoDB 缓冲池 MySQL InnoDB 事务 My ...
- Mysql中MVCC的使用及原理详解
准备 测试环境:Mysql 5.7.20-log 数据库默认隔离级别:RR(Repeatable Read,可重复读),MVCC主要适用于Mysql的RC,RR隔离级别 创建一张存储引擎为test ...
- 【MySQL】面试官:谈谈你对Mysql的MVCC的理解?
MVCC(Mutil-Version Concurrency Control),就是多版本并发控制.MVCC 是一种并发控制的方法,一般在数据库管理系统中,实现对数据库的并发访问. 在Mysql的In ...
- mysql 之mvcc多版本控制
MVCC是multiversion concurrency control的缩写,提供MySQL事物隔离级别下无锁读,例如一个事物在执行update等修改数据的sql,并未提交时其他事物进行数据读取是 ...
- MySQL InnoDB MVCC深度分析
关于MySQL的InnoDB的MVCC原理,很多朋友都能说个大概: 每行记录都含有两个隐藏列,分别是记录的创建时间与删除时间 每次开启事务都会产生一个全局自增ID 在RR隔离级别下 INSERT -& ...
- 《Mysql - 事务 MVCC》
一:前言 - 前面通过 <Mysql 事务 - 隔离> 的学习,知道了事务的实现,是根据 获取一致性视图 来实现的. 二:那么,什么时候会获取到一致性视图呢? - 例如:有三个事务,启动的 ...
随机推荐
- SpringBoot向Excel模板中写入数据并下载 (无需获取file对象及模板绝对路径)
之前用获取模板路径的方式测试没问题打包后就有问题了 莫名出现一个! 找了很多教程尝试无果 最终使用下面这个方式 无需获取file对象以及模板路径的方式进行写入下载 (那个设置浏览器编码没有测试不知道能 ...
- uni-app 动态修改主题色
老是碰到初版制作完成没多久,就整一出说什么要更改整个项目的色彩体系.真的是宝宝心里苦啊! 起初都是通过uni项目自带的uni.scss中定义,在替换页面上对应的css.以便于达到一次性修改整体布局的样 ...
- linux系统中安装虚拟机
在linux系统中,利用图形化界面安装虚拟机.首先启动 virt-manager,当然没有安装 virt-manager需要先安装好. 1 $ apt-get install virt-manager ...
- SpringBoot基础学习笔记
Springboot框架: springboot官网参考 Sringboot是整合spring技术栈的一站式框架,其简化配置,实现了自动化配置 Springboot基础结构: 1.pom.xml文件: ...
- [python] 基于NetworkX实现网络图的绘制
NETWORK CHART(网络图) 代码下载地址 网络图 (或图表或图形)显示了一组实体之间的互连.每个实体由一个或多个节点表示.节点之间的连接通过链接(或边)表示.网络的理论与实现是一个广阔的研究 ...
- 已完成 10000 多次提交,Solon Java Framework v1.12.1 发布
一个更现代感的 Java 应用开发框架:更快.更小.更自由.没有 Spring,没有 Servlet,没有 JavaEE:独立的轻量生态.主框架仅 0.1 MB. @Controller public ...
- Python Excel 追加数据
xlutils 库的安装 你好,我是悦创. 前面我分享了 Excel 的读写:Python 实现 Excel 的读写操作:https://bornforthis.cn/column/pyauto/au ...
- Windows 11 内核新调试器「GitHub 热点速览 v.23.01」
本周热点趋势榜虽然新项目不多,但是还是有几个不错值得收藏的工具项目,比如用来做文本转语音的 tortoise-tts 能生成更加贴近真实人声的语音,让 Golang 并发更出色的 conc,以及通过 ...
- 如何在mac电脑上配置命令行工具
Hi,欢迎大家在有空的时候做客[江涛学编程],这里是2023年的第7篇原创文章,今天我们来聊一聊如何在mac电脑上配置命令行工具 老规矩,拍拍手,上菜. 同学,打开你的mac电脑,按住键盘上的&quo ...
- linux 基础之输入输出重定向
输入输出重定向 输出重定向 正确命令 > 文件 (覆盖) 正确命令 >> 文件(追加) 错误命令 2> 文件(覆盖) 错误命令 2>>文件(追加) 命令> 文 ...