你是否对MySQL数据库中的事务已经有所了解?看下面这张图 , 按照1~6的顺序依次执行 , 在RR隔离级别下 , 事务A和事务B各自输出的num值是多少吗?
文章插图
我们预先创建好这样一张表并初始化一条数据:
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:
文章插图
事务A
事务B:
文章插图
事务B
事务C:
文章插图
事务C
按照上图的执行顺序执行commit , 其中事务C是自动提交事务的 , 不需要我们显示的commit , 事务A、B的输出结果如下:
事务A:num=1事务B:num=3
为什么是这样输出?它的背后其实是:MVCC(多版本并发控制)、consistent read(一致性读)、locking reads(锁定读)等MySQL数据库底层知识 。
1、MVCCMySQL数据库官网文档是这样来描述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)
2、一致性读(consistent read)继续看官方文档对consistent read的描述:
文章插图
【MySQL底层之MVCC、回滚段、一致性读、锁定读】
官网链接:https://dev.mysql.com/doc/refman/8.0/en/glossary.html#glos_consistent_read
直译:
一个读操作使用基于某个时刻的快照信息来显示查询结果 , 而不考虑同时运行的其他事务所执行的更改 。如果查询到的数据被其他事务所更改 , 则根据undo log中的内容来重建原始数据 。这种技术避免了一些通过强制事务等待其他事务完成而降低并发性的锁定问题 。
- 在RR级别下 , 首次读操作被执行时候创建一致性读视图ReadView , 事务的后续读都基于该视图的数据;
- 在RC级别下 , 每一次读操作都会创建一个最新的ReadView , 因此每次select读都可以获取到当前已提交事务的最新数据;
另外:
读未提交(read uncommitted)、串行化(serializable)是不需要依赖MVCC的 , 读未提交直接每次都读取当前数据的最新值即可 。而serializable是直接采用加锁的操作让所有的事务都串行化执行 , 牺牲了并发能力 。
推荐阅读
- 丝绸之路是在哪个时期开通的 丝绸之路最早是由谁开通的
- 黄山毛峰是绿茶么,绿茶之黄山毛峰
- 数据库:innodb数据组织形式
- 方腊之战中梁山死了几名好汉 梁山好汉有哪些被方腊杀死
- 嵇康是建安七子之一吗? 王粲是什么七子之一
- 清平乐村居表达了诗人什么之情 清平乐村居词人在词中勾勒了一幅怎样的画面
- 蓝田之战楚国如果赢了 秦楚蓝田之战真相
- |钓鱼高手轻易不告诉别人的5个钓鱼秘诀,掌握之后才能成为高手
- 后汉书王梁传 东汉梁太后之兄
- 赤壁之战之后形成了什么局面 赤壁之战形成了三国鼎立的局面吗