我劝!这位年轻人不讲MVCC,耗子尾汁!
Hi,大家好!我是白日梦。
今天我要跟你分享的话题是:“MySQL是如何根据undo log 链条实现read view机制的?谈谈看”
一、事物的隔离级别与MVCC?
MySQL单进程多线程的数据库软件,在事务的并发操作中可能会出现脏读,不可重复读,幻读。
MySQL支持的四种事务隔离级别如下:
Read uncommited
简单来说就是:事务A可以读到事务B未commit的数据。这种情况也被叫做脏读。
Read commited
简单来说就是:事务A可以读到事务B已经commit的数据。
Serializable
在该级别下,写会加写锁、读会加读锁,除了读读不互斥,其他组合都互斥,因此可以保证事务串行化顺序执行,可以避免脏读、不可重复读与幻读。
Repeatable read
如下图:可重复读要求事物A两次 select 查询出来的结果是一样的,即使中间事物B将id=1的行给修改了,也要保证事物A再读取时,读到的结果也得和第一次读到的结果相同。

但是可重复读存在幻读读问题,比如事物A开启后按某个范围X读取一次(事物未提交),这时其他事物在该范围X内插入了新的数据,事物A再读时就会将新插入的数据读取出来,当然在MySQL的RR隔离级别下不会再出现这种幻行的问题。
问题的解决得益于:MVCC多版本并发控制的快照读和next-key lock 当前读。
二、Repeatable Read是如何实现的
以RR隔离级别为例:
你可以像下面这样看一下你的MySQL默认使用的什么隔离级别:

MVCC多版本并发控制也被称为快照读,在RR的隔离级别下,当事物开启时会创建一个视图(Read View),其实这个视图就是所谓的快照。在整个事物存在的期间,一直会使用这个视图。
下面看一个九个步骤的小实验:

上图中的右部分的会话中begin之后,就会创建读视图,所以它的多次select使用的是同一个视图,所以结果都是一样的。即使数据中途被左边的事物更改了,它也没有受到影响。
再结合视图去理解这个过程。
当你执行begin开启事物之后,MySQL会拍下像下图这样的快照:

上图中的trx_ids中记录着MySQL中活跃的且未提交的事物。
假设有事物A、事物B擦不多在同一时刻开启,那这两个事物会分别得到如下的视图。

在RR的隔离级别下,事物一开启就会得到上图那样的ReadView,并且只要事物不提交这个ReadView就一直有效。
就上图来说:
在事物A的视图中,它的事物ID=61,此时活跃的事物集合是[61、62],活跃的事物ID中最小的事物id是它本身。下一个事物id应该是63。
在事物B的视图中,它的事物ID=621,此时活跃的事物集合是[61、62],活跃的事物ID中最小的事物id是61。下一个事物id应该是63。
先让事物A尝试去读取name列的数据。
它会发现的这行数据的Data_TRX_ID=60,通过和trx_ids对比发现这个事物ID不在活跃的事物id集合trx_ids中,并且小于它本身的60。说明:在事物A开启之前,事物ID=60的事物早就提交过了。所以事物A能直接这行数据name = tom。
然后事物B通过update语句尝试去修改这行数据,想将name 改成 jetty。这时MySQL会记录相应的undo log,并以链表的方式串联起来,于是我们会得到下图:

你可以看到上图中,由于事物B将name改成jerry,导致多出一条undo log。这条undo对应的事物ID=事物B的事物ID = 62。并且通过一个指针执向它的上一个undo log记录。
这时如果事物A重新去读,首先它会读取到的记录是name = jerry,但是它也会发现该记录的trx_id = 62 , 比自己的61还大,并且比下一个事物ID63小。说明:它读到记录其实是和自己同时开启的事物修改后的产物,这时他就会沿着undo log链条往前找,直到找到第一个trx_id等于或者小于自己事物ID的记录为止。所以事物A再一次读取到trx_id = 60的记录。
这也就是所谓的快照读机制。
另外需要注意的是:就上例来说,在RR的隔离级别下,确实能保证事物A每次读取出来的结果都是一样的,而且在事物B将其修改后,事物A依然能读取出name = tom。但是这时name=tom真的只是个快照,本质上它已经可以算是不存在是数据了。
本文是MySQL专题第15篇,全文近100篇(公众号首发)
本文是第15篇,全文近100篇,点击查看目录
三、Read Commited是如何实现的:
在RR隔离级别下,当事物一开始视图就会被创建出来,并且一直到该事物提交该视图都有效。
在Read Commited隔离级别,每次select 都会创建一个新的视图。
还是使用这个例子:假设事物A和事物B并发开启,并且各自得到了图中的ReadView。然后很快,事物B就将数据name = tom改成了name = jerry(未提交)。那这时事物A去select会检索出什么结果呢?
事物A检索过程:事物A首先会沿着undo log链条从头开始找,于是它首先找到name = jerry的列。但是它也发现该列的trx_id = 62 不但比自己的事物ID60大,而且还在trx_ids这个活跃事物列表中,说明name = jerry是被和自己差不多同时开启的其他事物更改的。它自然也就读不到。

紧接着事物B提交事物,然后事物A重新select会开启一个新的视图,得到如下图:
当事物A沿着undo log链条往下查找时,他发现首先发现的name = jerry的行的trx_id是62,竟然比自己的事物ID61还大,但是进一步发现,这个事务ID62并不在trx_ids中。说明,这个其实是已经被提交了的数据,那直接就意味着其实自己是允许读出这条数据的。这也就是所谓的读已提交机制。

### 四、长事物的风险
其实文章看到这里,长事物有什么风险你应该也可以感觉出来了。
事务迟迟不结束,就意味着它随时可能会访问到数据库中任何数据,所以只要是它们可能用的回滚记录,数据库都得为他们保留着。所以事物越长,相应的他对应的视图也就越大。
上一篇文章中白日梦有和大家介绍过 undo log 默认存放在共享表空间文件中,同时在SQL5.6 MySQL5.7在也允许你将undo log拿到单独的表空间中去,但是不论怎样,undo log总会以真实存在的文件的形式存在于磁盘上,当然了MySQL5.7的undo truncate机制 结合purge线程可以将不需要的undo log清除掉,为undo log文件瘦身,但是在这之前undo log的体量会不断的增大,再加上大量的长事物,很可能会将磁盘打爆。
另外长事物大概率是update等DML导致的,这种DML是会持有行锁的。谁也不能保证长时间不释放锁不会导致数据库被拖垮。
本文是MySQL专题第15篇,全文近100篇(公众号首发)
本文是第15篇,全文近100篇,点击查看目录
我劝!这位年轻人不讲MVCC,耗子尾汁!的更多相关文章
- Python爬取B站耗子尾汁、不讲武德出处的视频弹幕
本文的文字及图片来源于网络,仅供学习.交流使用,不具有任何商业用途,如有问题请及时联系我们以作处理. 前言 耗子喂汁是什么意思什么梗呢?可能很多人不知道,这个梗是出自马保国,经常上网的人可能听说过这个 ...
- JLC PCB 嘉立创自动确认生产稿,不讲武德?耗子尾汁!!!
首先,开局一张图,嘉立创又不做人的一天.嘉立创不讲武德,耗子尾汁!!! 之前下单,勾选了确定生产稿和不加客编,结果生产稿出来还是给我加了客编.那我出10元的意思何在?让我自己花3元看我花的10元有没有 ...
- CommandLineRunner 可能会导致你的应用宕机停止,我劝你耗子尾汁
hello,大家好,我是小黑,又和大家见面啦~~ 如果你去某度搜索关键词 CommandLineRunner 初始化资源 ,截止小黑同学写这篇推文之前,大概能收到 1,030,000 个结果. 网上大 ...
- 新同事不讲“码”德,这SQL写得太野了,请耗子尾汁~
今天来分享几个MySQL常见的SQL错误(不当)用法.我们在作为一个初学者时,很有可能自己在写SQL时也没有注意到这些问题,导致写出来的SQL语句效率低下,所以我们也可以自省自检一下. 1. LIMI ...
- 年轻人不讲武德来白piao我这个老同志
朋友们好啊,我是码农小胖哥. 今天有个同学问我在吗,我说什么事? 给我发个截图,我一看!噢,原来是帮忙搞个定时任务,还是动态的. 他说了两种选择,一种是用DelayQueue,一种是用消息队列. 他说 ...
- 年轻人不讲武德,竟然重构出这么优雅后台 API 接口
Hello,早上好,我是楼下小黑哥~ 最近偶然间在看到 Spring 官方文档的时候,新学到一个注解 @ControllerAdvice,并且成功使用这个注解重构我们项目的对外 API 接口,去除繁琐 ...
- 谈谈传说中的redo log是什么?有啥用?
目录 一.引出 redo log 的作用 二.思考一个问题: 三.redo log block 四.redo log buffer 五.redo log的刷盘时机 六.推荐参数 七.redo log ...
- 一起看下MySQL的崩溃恢复到底是怎么回事
目录 回顾 思考一个问题 checkponit机制 Checkpoint的种类及触发条件 LSN 推荐阅读 本文稍微有点晦涩.但是看过之后你就能Get到MySQL的崩溃恢复到底是怎么做的! 文章公号 ...
- MySQL的binlog有啥用?谁写的?在哪里?怎么配置
目录 一.唠嗑 二.什么是bin log? 三.它在哪里? 四.bin log的相关配置 五.binlog 有啥用? 六.超有用的参数 sql_log_bin 七.未来几篇文章 推荐阅读 一.唠嗑 文 ...
随机推荐
- 2020 年TI 杯大学生电子设计竞赛E题总结(放大器非线性失真研究装置)
2020年TI杯大学生电子设计竞赛E题总结(放大器非线性失真研究装置) 摘要:E题的竞赛内容主要是参赛者自己搭建一个晶体管放大器,能够产生不失真.顶部失真.底部失真.双向失真和交越失真五种波形,并分别 ...
- logback日志打印sql
今天整合springboot2 + mybatis + logback 遇到了在日志中sql打印不出来的坑,在网上找了好久,都不是我遇到的问题,这里吐槽一下下现在的博客质量,好多都是抄袭的,也没有标注 ...
- 归档空间满了 导致Imp卡住
今天在使用exp imp将生产环境数据库导入到测试环境的过程中,imp的时候 发现在导入某张表的时候卡住了. 起初是以为该表比较大的缘故,后来过了很久 发现还是卡在那里. 最后分析原因 发现设置的归档 ...
- CodeChef-RNDRATIO Mysterious Ratio 题解
CodeChef-RNDRATIO Mysterious Ratio 题意简述: 对每个 \(1 \le i \le n\) ,随机选择一个数 \(A_i\) ,满足 \(L_i \le A_i \l ...
- CSS两列布局的多种方式
两列布局(一侧固定宽度,一侧自适应),在工作中应该是经常使用到,可以说是前端基础了.这种两列布局的样式是我们在平时工作中非常常见的设计,同时也是面试中要求实现的高频题.很有必要掌握以备不时之需.这里总 ...
- day90:luffy:路飞项目前端部署
目录 1.域名备案 2.域名解析 3.设置安全组 4.部署架构图 5.一些准备工作 6.docker 7.把前端项目通过nginx容器来运行 1.域名备案 腾讯云先要进行域名实名认证,实名认证三天后才 ...
- JS 实现飞机大战
这是JS版本的飞机大战,和C#版本的思路相同,就是语言上有差别,用来巩固知识.可以将代码直接引入到HTML中就可以看到效果 //编写背景对象 function Background(width,hei ...
- 1-06-2 Lambda表达式
last modified:2020/10/31 1-06-3-Lambda表达式 6.3.1 为什么引入lambda表达式 lambda表达式是一个可传递的代码块,可以在以后执行一次或多次. 将一个 ...
- Ceph数据盘怎样实现自动挂载
前言 在Centos7 下,现在采用了 systemctl来控制服务,这个刚开始用起来可能不太习惯,不过这个服务比之前的服务控制要强大的多,可以做更多的控制,本节将来介绍下关于 Ceph的 osd 磁 ...
- Ceph部署的时候修改默认权重
前言 部署集群的时候权重是默认生成的,这个是根据磁盘大小分配的,我们有的时候需要去修改一下这个默认权重 修改 如果统一的初始值,那么直接添加参数即可 osd_crush_initial_weight ...