MySQL底层之MVCC、回滚段、一致性读、锁定读

你是否对MySQL数据库中的事务已经有所了解?看下面这张图 , 按照1~6的顺序依次执行 , 在RR隔离级别下 , 事务A和事务B各自输出的num值是多少吗?

MySQL底层之MVCC、回滚段、一致性读、锁定读

文章插图
 
我们预先创建好这样一张表并初始化一条数据:
CREATE TABLE `test1`(`id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键Id',`num` int(11) NULL COMMENT '数量',PRIMARY KEY (`id`)) ENGINE = InnoDB;insert into test1(id, num) values (1, 1);然后开始按上图的顺序执行各个事务 , 这需要我们打开3个操作窗口来分别执行A、B、C三个事务:
事务A:
MySQL底层之MVCC、回滚段、一致性读、锁定读

文章插图
事务A
事务B:
MySQL底层之MVCC、回滚段、一致性读、锁定读

文章插图
事务B
事务C:
MySQL底层之MVCC、回滚段、一致性读、锁定读

文章插图
事务C
按照上图的执行顺序执行commit , 其中事务C是自动提交事务的 , 不需要我们显示的commit , 事务A、B的输出结果如下:
事务A:num=1事务B:num=3为什么是这样输出?
它的背后其实是:MVCC(多版本并发控制)、consistent read(一致性读)、locking reads(锁定读)等MySQL数据库底层知识 。
1、MVCCMySQL数据库官网文档是这样来描述MVCC的:
MySQL底层之MVCC、回滚段、一致性读、锁定读

文章插图
 
官网链接:https://dev.mysql.com/doc/refman/8.0/en/innodb-multi-versioning.html
淘宝的数据库内核月报中有提到(文末有文章链接):
多版本控制: 指的是一种提高并发的技术 。最早的数据库系统 , 只有读读之间可以并发 , 读写 , 写读 , 写写都要阻塞 。引入多版本之后 , 只有写写之间相互阻塞 , 其他三种操作都可以并行 , 这样大幅度提高了InnoDB的并发度 。在内部实现中 , 与Postgres在数据行上实现多版本不同 , InnoDB是在undolog中实现的 , 通过undolog可以找回数据的历史版本 。找回的数据历史版本可以提供给用户读(按照隔离级别的定义 , 有些读请求只能看到比较老的数据版本) , 也可以在回滚的时候覆盖数据页上的数据 。在InnoDB内部中 , 会记录一个全局的活跃读写事务数组 , 其主要用来判断事务的可见性 。
目前来看MVCC的实现依赖于:
  • 隐藏字段(DB_TRX_ID、DB_ROLL_PTR)
  • 回滚日志(undo log)
  • 一致性读(consistent read)
你也可以这样去理解MVCC:一个事务对数据进行更新操作时候 , 先把旧的数据放到一个单独的地方(回滚段) , 其他事务读取数据时候 , 根据DB_TRX_ID、DB_ROLL_PTR计算出undo log链中当前版本的数据 。
2、一致性读(consistent read)继续看官方文档对consistent read的描述:
MySQL底层之MVCC、回滚段、一致性读、锁定读

文章插图
【MySQL底层之MVCC、回滚段、一致性读、锁定读】 
官网链接:https://dev.mysql.com/doc/refman/8.0/en/glossary.html#glos_consistent_read
直译:
一个读操作使用基于某个时刻的快照信息来显示查询结果 , 而不考虑同时运行的其他事务所执行的更改 。如果查询到的数据被其他事务所更改 , 则根据undo log中的内容来重建原始数据 。这种技术避免了一些通过强制事务等待其他事务完成而降低并发性的锁定问题 。
  1. 在RR级别下 , 首次读操作被执行时候创建一致性读视图ReadView , 事务的后续读都基于该视图的数据;
  2. 在RC级别下 , 每一次读操作都会创建一个最新的ReadView , 因此每次select读都可以获取到当前已提交事务的最新数据;
“一致性读”是InnoDB引擎在RC和RR隔离级别下处理select语句的默认模式 。因为一个“一致性读”是不需要对它访问的表设置任何的锁 , 当对表执行“一致性读”时候 , 其他会话可以自由的修改这些表 。
另外:
读未提交(read uncommitted)、串行化(serializable)是不需要依赖MVCC的 , 读未提交直接每次都读取当前数据的最新值即可 。而serializable是直接采用加锁的操作让所有的事务都串行化执行 , 牺牲了并发能力 。


推荐阅读