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

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

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

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

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

# session Amysql> 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事务隔离级别没有任何区别。

如上图所示,当会话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进行转账操作。转账操作和查询总额操作的时序图如下图所示。

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

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

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

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

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、事务号dbtrxid和回滚指针dbrollptr,其中dbtrxid表示最近修改的事务的id,dbrollptr指向回滚段中的undo log。如下图所示。

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

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

REPEATABLE READ隔离级别下事务开始后使用MVVC机制进行读取时,会将当时活动的事务id记录下来,记录到Read View中。READ COMMITTED隔离级别下则是每次读取时都创建一个新的Read View。 Read View是InnoDB中用于判断记录可见性的数据结构,记录了一些用于判断可见性的属性。lowlimitid:某行记录的dbtrxid < 该值,则该行对于当前Read View是一定可见的

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

lowlimitno:用于purge操作的判断

rwtrxids:读写事务数组

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

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

如果dbtrxid大于或者等于lowlimitid,则该记录对于该Read View一定是不可见的。如果dbtrxid位于[uplimitid, lowlimitid)范围内,需要在活跃读写事务数组(rwtrxids)中查找dbtrxid是否存在,如果存在,记录对于当前Read View是不可见的。 如果记录对于Read View不可见,需要通过记录的DBROLLPTR指针遍历undo log,构造对当前Read View可见版本数据。 简单来说,Read View记录读开始时及其之后,所有的活动事务,这些事务所做的修改对于Read View是不可见的。除此之外,所有其他的小于创建Read View的事务号的所有记录均可见。

后记

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

hiw个人博客:Carpediem​remcarpediem.net

参考文章

mysql+一致性非锁定读_MySQL探秘(六):InnoDB一致性非锁定读相关推荐

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

    一致性非锁定读(consistent nonlocking read)是指InnoDB存储引擎通过多版本控制(MVVC)读取当前数据库中行数据的方式.如果读取的行正在执行DELETE或UPDATE操作 ...

  2. MySQL探秘(六):InnoDB一致性非锁定读(隔离性)

    一致性非锁定读(consistent nonlocking read)是指InnoDB存储引擎通过多版本控制(MVVC)读取当前数据库中行数据的方式.如果读取的行正在执行DELETE或UPDATE操作 ...

  3. mysql 额外内存池_MySQL探秘(三):InnoDB的内存结构和特性

    常言说得好,每个成功男人背后都有一个为他默默付出的女人,而对于MySQL来说,这个"人"就是InnoDB存储引擎. MySQL区别于其他数据库的最为重要的特点就是其插件式的表存储引 ...

  4. mysql 开启引擎命令_MySql中启用InnoDB数据引擎的方法

    1.存储引擎是什么? Mysql中的数据用各种不同的技术存储在文件(或者内存)中.这些技术中的每一种技术都使用不同的存储机制.索引技巧.锁定水平并且最终提供广泛的不同的功能和能力.通过选择不同的技术, ...

  5. mysql sql执行过程_MySQL探秘(二):SQL语句执行过程详解

    昔日庖丁解牛,未见全牛,所赖者是其对牛内部骨架结构的了解,对于MySQL亦是如此,只有更加全面地了解SQL语句执行的每个过程,才能更好的进行SQL的设计和优化. 当希望MySQL能够以更高的性能运行查 ...

  6. mysql 分区 mycat 分片_Mysql系列六:(Mycat分片路由原理、Mycat常用分片规则及对应源码介绍)...

    一.Mycat分片路由原理 我们先来看下面的一个SQL在Mycat里面是如何执行的: select * from travelrecord where id in(5000001, 10000001) ...

  7. 3种mysql的储存机制_MySQL三种InnoDB、MyISAM和MEMORY存储引擎对比

    三种引擎的区别: 事务:InnoDB支持事务,MyISAM和MEMORY两个不支持. 存储限制:InnoDB有64TB的存储限制,MyISAM和MEMORY要跟具体情况而定. 空间使用:InnoDB对 ...

  8. mysql 模糊查询用法_mysql进阶(六)模糊查询的四种用法介绍

    mysql中模糊查询的四种用法介绍 这篇文章主要介绍了mysql中模糊查询的四种用法,需要的朋友可以参考下. 下面介绍mysql中模糊查询的四种用法: 1 %: 表示任意0个或多个字符.可匹配任意类型 ...

  9. MySQL探秘(七):InnoDB行锁算法

     在上一篇<InnoDB一致性非锁定读>中,我们了解到InnoDB使用一致性非锁定读来避免在一般的查询操作(SELECT FOR UPDATE等除外)时使用锁.然而锁这个事情是无法避免的, ...

最新文章

  1. oracle11g安装中的问题
  2. usb2.0/3.0/3.1/3.2/4 各版本速率
  3. 【NBIoT无线模块DTU数传电台】串口服务器RS232/RS485端口工业路由信号传输
  4. 项目总结:华南师范大学校园开发教育android客户端总结
  5. 650c公路车推荐_盘点2020年各价位高性价比入门公路车
  6. 项目管理学习笔记二:信息系统服务管理
  7. (95)分频器设计(偶数分频)
  8. C#设计模式-策略者模式
  9. Odoo10教程---模块化三:模型约束,高级视图,工作流,安全性,向导,国际化和报表等
  10. LVS+Keepalive+Nginx实现负载均衡
  11. [置顶] asp.net(c#)中相对路径(虚拟路径)和物理磁盘路径的转换
  12. 前端模块化概念及规范之一commonjs
  13. 学习码 滚动码 固定码 有什么区别重码数,编码容量滚动码的原理
  14. 松下电视机服务器未响应,松下等离子电视机通病有哪些 教你如何解决
  15. 便捷开票二维码应用规范中的那些坑
  16. epoch如何设置,在Keras中,steps_per_epoch和纪元的设置如何影响训练结果?
  17. 图文解读 Infor10 ERP SyteLine的功能
  18. CSS3 制作旋转的大风车
  19. Tomcat:The valid characters are defined in RFC 7230 and RFC 3986 问题处理
  20. 浚县天气预报软件测试,浚县天气预报15天

热门文章

  1. 阿里云获全球第一张云安全国际认证金牌
  2. canvas学习-----1px线条模糊问题
  3. ES6 import export
  4. Spring Resource接口获取资源
  5. 检测IP地址的正则表达式
  6. 【转】JavaScript eval处理JSON数据 为什么要加括号
  7. uva 10985 Rings'n'Ropes
  8. IT公司比较流行的10种编程语言
  9. zzulioj 1120: 最值交换
  10. 信息学奥赛一本通 2043:【例5.11】杨辉三角形