(三) 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 事务 - 隔离> 的学习,知道了事务的实现,是根据 获取一致性视图 来实现的. 二:那么,什么时候会获取到一致性视图呢? - 例如:有三个事务,启动的 ...
随机推荐
- Graph Neural Network——图神经网络
本文是跟着李沐老师的论文精度系列进行GNN的学习的,详细链接请见:零基础多图详解图神经网络(GNN/GCN)[论文精读] 该论文的标题为<A Gentle Introduction to Gra ...
- Python函数用法和底层分析
目录 Python函数用法和底层分析 函数的基本概念 Python 函数的分类 核心要点 形参和实参 文档字符串(函数的注释) 返回值 函数也是对象,内存底层分析 变量的作用域(全局变量和局部变量) ...
- [深度学习] tf.keras入门2-分类
目录 Fashion MNIST数据库 分类模型的建立 模型预测 总体代码 主要介绍基于tf.keras的Fashion MNIST数据库分类, 官方文档地址为:https://tensorflow. ...
- python之路49 模板层标签 自定义过滤器 模板继承、模型层准备、ORM部分操作
模板层之标签 {% if 条件1(可以自己写也可以是用传递过来的数据) %} <p>周三了 周三了</p> {% elif 条件2(可以自己写也可以用传递过来的数据) %} & ...
- C++string与int的相互转换(使用C++11)
一.int转string #include <iostream> #include <string> int main() { double f = 23.43; double ...
- day04-Spring管理Bean-IOC-02
Spring管理Bean-IOC-02 2.基于XML配置bean 2.7通过util空间名称创建list BookStore.java: package com.li.bean; import ja ...
- 微机原理与系统设计笔记2 | 8086CPU结构与功能
打算整理汇编语言与接口微机这方面的学习记录.本部分讲解8086CPU的结构和基本功能以及特性. 参考资料 西电<微机原理与系统设计>周佳社 西交<微机原理与接口技术> 课本&l ...
- Python自动批量修改文件名称的方法
本文介绍基于Python语言,按照一定命名规则批量修改多个文件的文件名的方法. 已知现有一个文件夹,其中包括班级所有同学上交的作业文件,每人一份:所有作业文件命名格式统一,都是地信1701_姓 ...
- 大数据实时多维OLAP分析数据库Apache Druid入门分享-下
@ 目录 架构 核心架构 外部依赖 核心内容 roll-up预聚合 列式存储 Datasource和Segments 位图索引 数据摄取 查询 集群部署 部署规划 前置条件 MySQL配置 HDFS配 ...
- Unity - 自定义Log
嗨,崽崽们大家好.实在是不知道写个啥了,最近总是恍惚,今儿偷个懒吧,给大家推荐一个小黑自己写的小型日志工具,在一些小项目中管够使用了. 那有人会问了,Unity不是自带日志么,为什么还要自己做个小工具 ...