mysql取消mvvc机制_MySQL探秘(六):InnoDB一致性非锁定读

一致性非锁定读(consistent nonlocking read)是指InnoDB存储引擎通过多版本控制(MVVC)读取当前数据库中行数据的方式。如果读取的行正在执行DELETE或UPDATE操作,这时读取操作不会因此去等待行上锁的释放。相反地,InnoDB会去读取行的一个快照。

47af9a05ce9c25a7eaaa5b5539ad5263.png

上图直观地展现了InnoDB一致性非锁定读的机制。之所以称其为非锁定读,是因为不需要等待行上排他锁的释放。快照数据是指该行的之前版本的数据,每行记录可能有多个版本,一般称这种技术为行多版本技术。由此带来的并发控制,称之为多版本并发控制(Multi Version Concurrency Control, MVVC)。InnoDB是通过undo log来实现MVVC。undo log本身用来在事务中回滚数据,因此快照数据本身是没有额外开销。此外,读取快照数据是不需要上锁的,因为没有事务需要对历史的数据进行修改操作。

一致性非锁定读是InnoDB默认的读取方式,即读取不会占用和等待行上的锁。但是并不是在每个事务隔离级别下都是采用此种方式。此外,即使都是使用一致性非锁定读,但是对于快照数据的定义也各不相同。

在事务隔离级别READ COMMITTED和REPEATABLE READ下,InnoDB使用一致性非锁定读。然而,对于快照数据的定义却不同。在READ COMMITTED事务隔离级别下,一致性非锁定读总是读取被锁定行的最新一份快照数据。而在REPEATABLE READ事务隔离级别下,则读取事务开始时的行数据版本。

我们下面举个例子来详细说明一下上述的情况。

# session A

mysql> BEGIN;

mysql> SELECT * FROM test WHERE id = 1;

我们首先在会话A中显示地开启一个事务,然后读取test表中的id为1的数据,但是事务并没有结束。于此同时,用户在开启另一个会话B,这样可以模拟并发的操作,然后对会话B做出如下的操作:

# session B

mysql> BEGIN;

mysql> UPDATE test SET id = 3 WHERE id = 1;

在会话B的事务中,将test表中id为1的记录修改为id=3,但是事务同样也没有提交,这样id=1的行其实加了一个排他锁。由于InnoDB在READ COMMITTED和REPEATABLE READ事务隔离级别下使用一致性非锁定读,这时如果会话A再次读取id为1的记录,仍然能够读取到相同的数据。此时,READ COMMITTED和REPEATABLE READ事务隔离级别没有任何区别。

2123d2a53e7ac87059b1f1626cc485b8.png

如上图所示,当会话B提交事务后,会话A再次运行SELECT * FROM test WHERE id = 1的SQL语句时,两个事务隔离级别下得到的结果就不一样了。

对于READ COMMITTED的事务隔离级别,它总是读取行的最新版本,如果行被锁定了,则读取该行版本的最新一个快照。因为会话B的事务已经提交,所以在该隔离级别下上述SQL语句的结果集是空的。

对于REPEATABLE READ的事务隔离级别,总是读取事务开始时的行数据,因此,在该隔离级别下,上述SQL语句仍然会获得相同的数据。

MVVC

我们首先来看一下wiki上对MVVC的定义:

Multiversion concurrency control (MCC or MVCC), is a concurrency control

method commonly used by database management systems to provide

concurrent access to the database and in programming languages to

implement transactional memory.

由定义可知,MVVC是用于数据库提供并发访问控制的并发控制技术。

数据库的并发控制机制有很多,最为常见的就是锁机制。锁机制一般会给竞争资源加锁,阻塞读或者写操作来解决事务之间的竞争条件,最终保证事务的可串行化。而MVVC则引入了另外一种并发控制,它让读写操作互不阻塞,每一个写操作都会创建一个新版本的数据,读操作会从有限多个版本的数据中挑选一个最合适的结果直接返回,由此解决了事务的竞争条件。

考虑一个现实场景。管理者要查询所有用户的存款总额,假设除了用户A和用户B之外,其他用户的存款总额都为0,A、B用户各有存款1000,所以所有用户的存款总额为2000。但是在查询过程中,用户A会向用户B进行转账操作。转账操作和查询总额操作的时序图如下图所示。

bd9c82be7c27beb4e737a9c5c7cafbf8.png

如果没有任何的并发控制机制,查询总额事务先读取了用户A的账户存款,然后转账事务改变了用户A和用户B的账户存款,最后查询总额事务继续读取了转账后的用户B的账号存款,导致最终统计的存款总额多了100元,发生错误。

使用锁机制可以解决上述的问题。查询总额事务会对读取的行加锁,等到操作结束后再释放所有行上的锁。因为用户A的存款被锁,导致转账操作被阻塞,直到查询总额事务提交并将所有锁都释放。

f8f98b0a446a189b597c7d41623e5dd3.png

但是这时可能会引入新的问题,当转账操作是从用户B向用户A进行转账时会导致死锁。转账事务会先锁住用户B的数据,等待用户A数据上的锁,但是查询总额的事务却先锁住了用户A数据,等待用户B的数据上的锁。

使用MVVC机制也可以解决这个问题。查询总额事务先读取了用户A的账户存款,然后转账事务会修改用户A和用户B账户存款,查询总额事务读取用户B存款时不会读取转账事务修改后的数据,而是读取本事务开始时的数据副本(在REPEATABLE READ隔离等级下)。

dbfa09fabd58cfa70a9c43e6f907ddfa.png

MVCC使得数据库读不会对数据加锁,普通的SELECT请求不会加锁,提高了数据库的并发处理能力。借助MVCC,数据库可以实现READ COMMITTED,REPEATABLE READ等隔离级别,用户可以查看当前数据的前一个或者前几个历史版本,保证了ACID中的I特性(隔离性)

InnoDB的MVVC实现

多版本并发控制仅仅是一种技术概念,并没有统一的实现标准, 其的核心理念就是数据快照,不同的事务访问不同版本的数据快照,从而实现不同的事务隔离级别。虽然字面上是说具有多个版本的数据快照,但这并不意味着数据库必须拷贝数据,保存多份数据文件,这样会浪费大量的存储空间。InnoDB通过事务的undo日志巧妙地实现了多版本的数据快照。

数据库的事务有时需要进行回滚操作,这时就需要对之前的操作进行undo。因此,在对数据进行修改时,InnoDB会产生undo log。当事务需要进行回滚时,InnoDB可以利用这些undo log将数据回滚到修改之前的样子。

根据行为的不同 undo log 分为两种 insert undo log和update undo log。

insert undo log 是在 insert 操作中产生的 undo log。因为 insert 操作的记录只对事务本身可见,对于其它事务此记录是不可见的,所以 insert undo log 可以在事务提交后直接删除而不需要进行 purge 操作。

update undo log 是 update 或 delete 操作中产生的 undo log,因为会对已经存在的记录产生影响,为了提供 MVCC机制,因此 update undo log 不能在事务提交时就进行删除,而是将事务提交时放到入 history list 上,等待 purge 线程进行最后的删除操作。

为了保证事务并发操作时,在写各自的undo log时不产生冲突,InnoDB采用回滚段的方式来维护undo log的并发写入和持久化。回滚段实际上是一种 Undo 文件组织方式。

InnoDB行记录有三个隐藏字段:分别对应该行的rowid、事务号db_trx_id和回滚指针db_roll_ptr,其中db_trx_id表示最近修改的事务的id,db_roll_ptr指向回滚段中的undo log。如下图所示。

c070b51c33d1f572c6c73ae6f7f54e73.png

当事务2使用UPDATE语句修改该行数据时,会首先使用排他锁锁定改行,将该行当前的值复制到undo log中,然后再真正地修改当前行的值,最后填写事务ID,使用回滚指针指向undo log中修改前的行。如下图所示。

2bcd8cd0c092cc7df26b5e4132a5ff85.png

当事务3进行修改与事务2的处理过程类似,如下图所示。

9882cdccd181eb66f6048c8a642d519a.png

REPEATABLE READ隔离级别下事务开始后使用MVVC机制进行读取时,会将当时活动的事务id记录下来,记录到Read View中。READ COMMITTED隔离级别下则是每次读取时都创建一个新的Read View。

Read View是InnoDB中用于判断记录可见性的数据结构,记录了一些用于判断可见性的属性。

low_limit_id:某行记录的db_trx_id < 该值,则该行对于当前Read View是一定可见的

up_limit_id:某行记录的db_trx_id >= 该值,则该行对于当前read view是一定不可见的

low_limit_no:用于purge操作的判断

rw_trx_ids:读写事务数组

Read View创建后,事务再次进行读操作时比较记录的db_trx_id和Read View中的low_limit_id,up_limit_id和读写事务数组来判断可见性。

如果该行中的db_trx_id等于当前事务id,说明是事务内部发生的更改,直接返回该行数据。否则的话,如果db_trx_id小于up_limit_id,说明是事务开始前的修改,则该记录对当前Read View是可见的,直接返回该行数据。

如果db_trx_id大于或者等于low_limit_id,则该记录对于该Read View一定是不可见的。如果db_trx_id位于[up_limit_id, low_limit_id)范围内,需要在活跃读写事务数组(rw_trx_ids)中查找db_trx_id是否存在,如果存在,记录对于当前Read View是不可见的。

如果记录对于Read View不可见,需要通过记录的DB_ROLL_PTR指针遍历undo log,构造对当前Read View可见版本数据。

简单来说,Read View记录读开始时及其之后,所有的活动事务,这些事务所做的修改对于Read View是不可见的。除此之外,所有其他的小于创建Read View的事务号的所有记录均可见。

后记

我们后续还会学习InnoDB的锁的相关的知识,请大家持续关注。

76fdc81068e428153d3d7e42ea177d6e.png

参考文章

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/395852.shtml

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

相关文章

自动化脚本

自动化脚本工具: http://appium.io/slate/cn/master/?python#about-appium 查看app元素工具: uiautomatorviewer http://www.cnblogs.com/ITGirl00/p/4235466.html app 反编译原理 http://blog.csdn.net/jiangwei0910410003/article/details/47188679转载于:https://www.cnblo…

springmvc常用注解之@Controller和@RequestMapping

对于各种注解而言&#xff0c;排第一的当然是“Controller”,表明某类是一个controller。 “RequestMapping”请求路径映射&#xff0c;如果标注在某个controller的类级别上&#xff0c;则表明访问此类路径下的方法都要加上其配置的路径&#xff1b;最常用是标注在方法上&…

最小可行产品是什么_无论如何,“最小可行产品”到底意味着什么?

最小可行产品是什么by Ravi Vadrevu通过拉维瓦德雷武(Ravi Vadrevu) 无论如何&#xff0c;“最小可行产品”实际上是什么意思&#xff1f; (What does “Minimum Viable Product” actually mean, anyway?) 伊隆马斯克(Elon Musk)提出一个令人困惑的想法 (Elon Musk on makin…

站立会议12-2

编写团队博客&#xff0c;进行资料的查看转载于:https://www.cnblogs.com/qijun1120/p/10247725.html

彻底删除mysql server 2005_sql2005卸载工具(sql server 2005卸载工具)

如果您要安装新版的sql就必须先完整的卸载sql2005&#xff0c;如果你按照常规的方法是不能完整的卸载sql2005&#xff0c;从而会引起安装的时候说sql已经挂起的错误&#xff0c;sql2005卸载工具(sql server 2005卸载工具)&#xff0c;是一个帮你完整的清理已经安装的sql的工具。…

谷歌浏览器有时会卡顿_Google不会,不要学:为什么搜索有时会比了解更好

谷歌浏览器有时会卡顿by Jeremy Gunter杰里米甘特(Jeremy Gunter) Google不会&#xff0c;不要学&#xff1a;为什么搜索有时会比了解更好 (Google not, learn not: why searching can sometimes be better than knowing) A few months ago, I was reading through some of th…

codevs 1907 方格取数 3

Description 在一个有m*n 个方格的棋盘中&#xff0c;每个方格中有一个正整数。现要从方格中取数&#xff0c;使任意2 个数所在方格没有公共边&#xff0c;且取出的数的总和最大。试设计一个满足要求的取数算法。 Input 第1 行有2 个正整数m和n&#xff0c;分别表示棋盘的行数和…

APP应用 HTTP/1.0中keep-alive

在HTTP/1.0中keep-alive不是标准协议&#xff0c;客户端必须发送Connection:Keep-Alive来激活keep-alive连接。https://www.imooc.com/article/31231HTTP协议是无状态的协议&#xff0c;即每一次请求都是互相独立的。因此它的最初实现是&#xff0c;每一个http请求都会打开一个…

mysql 日期滞后_如何滞后MySQL中的列?

要在MySQL中滞后一列&#xff0c;首先让我们创建一个表。创建表的查询如下-mysql> create table LagDemo-> (-> UserId int,-> UserValue int-> );示例使用insert命令在表中插入一些记录。查询如下-mysql> insert into LagDemo values(12,158);mysql> ins…

oracle高效分页查询总结

本文参考链接&#xff1a;http://blog.sina.com.cn/s/blog_8604ca230100vro9.html 探索查询语句&#xff1a; --分页参数&#xff1a;size 20 page 2 --没有order by的查询 -- 嵌套子查询&#xff0c;两次筛选&#xff08;推荐使用&#xff09; --SELECT * -- FROM (SELECT R…

18124 N皇后问题

18124 N皇后问题 时间限制:2000MS 内存限制:65535K提交次数:0 通过次数:0 题型: 编程题 语言: G;GCC;VC Description 有N*N的国际象棋棋盘&#xff0c;要求在上面放N个皇后&#xff0c;要求任意两个皇后不会互杀&#xff0c;有多少种不同的放法&#xff1f; 输入格式 每一个…

ux设计师怎样找同类产品_没有预算? 别找借口。 便宜的UX上的UX 2:让我们开始构建。...

ux设计师怎样找同类产品by Vinny文尼 没有预算&#xff1f; 别找借口。 便宜的UX上的UX 2&#xff1a;让我们开始构建。 (No budget? No excuse. UX on the cheap Part 2: let’s get building.) This is a continuation of my series on ‘UX on a Budget’. If you haven’…

巨蟒python全栈开发-第6天 is==

1.小数据池 2.id 3.decode和encode 小数据池 #小数据池:不要死磕就行#python为了简化,搞出来的一个东西ID (1)# id()函数可以帮我们查看一个变量的内存地址# a10# b30# c10# print(id(a)) #1712876864# print(id(b)) #1712877504# print(id(c)) #1712876864(2)# lst[周…

安装mysql8._安装MySQL8(附详细图文)

安装MySQL8(附详细图文)删除mysql服务&#xff1a;mysqld -remove mysql1、下载 mysql 8下载地址&#xff1a;https://dev.mysql.com/downloads/mysql/2、配置 mysql 配置文件打开 mysql 8 的安装目录&#xff1a;my.ini注意设置自己对应的 mysql 安装目录 和数据存放目录[mysq…

win10安装windows live writer 错误:OnCatalogResult:0x80190194

到官网下载了一个在线安装程序&#xff0c;可是一运行就提示无法安装&#xff0c;显式错误“OnCatalogResult:0x80190194”&#xff0c;如下图所示 找到windows live安装程序的安装日志文件。具体位置是&#xff1a;C:\Users\All Users\Microsoft\WLSetup\Logs 需要下载安装文件…

C# 实现一个可取消的多线程操作 示例

private void button1_Click(object sender, EventArgs e){//定义一个为可取消资源标志CancellationTokenSource cts new CancellationTokenSource();//定义二个为可取消资源标志CancellationTokenSource cts1 new CancellationTokenSource();//实现一个可取消操作的回调函数…

这些工具将提高您的Android生产率

by Michal Bialas由Michal Bialas 这些工具将提高您的Android生产率 (These tools will boost your Android productivity) The main purpose of this post is to list and describe tools (mainly free ones), which allow you to boost your productivity, efficiency, and …

python四位玫瑰数的解题思路_入门python知识点总结以及15道题的解题思路分析

知识点总结python1、序列app操做符idex in s 若是x是列表s的元素&#xff0c;返回True&#xff0c;不然Falses t 链接两个序列s和ts*n或者n*s 将序列s复制n次s[i] 返回s中第i元素s[i:j]或s[i:j: k] 切片&#xff0c;返回序列s中第i到j-1以k为步长的元素子序列函数函数len(s) 返…

TZOJ--5480: 孤衾易暖 // POJ--3735 Training little cats (矩阵快速幂)

5480: 孤衾易暖 时间限制(普通/Java):1000MS/3000MS 内存限制:65536KByte 描述 哇&#xff0c;好难&#xff0c;我要放弃了(扶我起来&#xff0c;我还能A 寒夜纵长&#xff0c;孤衾易暖&#xff0c;钟鼓渐清圆。 生活也许有些不如意的地方&#xff0c;但是没有什么是拥有一…

IntelliJ IDEA2017 修改缓存文件的路径

IDEA的缓存文件夹.IntelliJIdea2017.1&#xff0c;存放着IDEA的破解密码&#xff0c;各个项目的缓存&#xff0c;默认是在C盘的用户目录下&#xff0c;目前有1.5G大小。现在想要把它从C盘移出。 在IDEA的安装路径下中&#xff0c;进入bin目录后找到属性文件&#xff1a;idea.pr…