八、undo log的类型#
undo log有两种类型,分别是 insert undo log 和 update undo log。
前者记录的是insert 语句对应的undo log。
后者对应的是 update、delete 语句对应的undo log。
九、insert undo log 长啥样?#
对于 insert 类型的sql,会在undo log中记录下方才你insert 进来的数据的ID,根据ID完成精准的删除。
insert 类型的undo log长下面这样:
可能你打眼一看上图就能知道各部分都有啥用。
但是,不知道你会不会纳闷这样一个问题:不是说对于insert 类型的undo log MySQL记录的是方才插入行ID吗?怎么上图整出来的了这么多Col1、Col2、Col2。
其实是MySQL设计的很周到,因为它是针对联合主键设计的。
十、一条update undo log 长啥样?#
一条update sql对应undolog长如下这样。
其实我感觉没必要记住这个图,记住了也会忘。大概看一下它长什么样子就好。
重点是下面会分享的,undo log链条,并且你得知道这个链条可以帮你实现事务的回滚
十一、事务是如何回滚的?(undo log 链条)#
举个例子:
对于 insert 类型的sql,会在undo log中记录下方才你insert 进来的数据的ID,当你想roll back时,根据ID完成精准的删除。
对于delete类型的sql,会在undo log中记录方才你删除的数据,当你回滚时会将删除前的数据insert 进去。
对于update类型的sql,会在undo log中记录下修改前的数据,回滚时只需要反向update即可。
对于select类型的sql,别费心了,select不需要回滚。
先看一个简单的insert undo log 链条
有一个注意点:因为单纯的insert sql不涉及多MVCC的能力。
所以一旦事务commit,这条insert undo log就可以直接删除了。
再看一个update类型的undo log
为了方便画图,重点突出链条的概念我省略了update undo log的部分内容
一个事务A开启后插图了一条记录:name = tom,MySQL会记录下这样一条undo log
随后先后来了两个事务:
事务B,事务ID=61,它执行sql将name 改成jerry。
事务C,事务ID=62,它执行sql将name 改成tom。
于是MySQL记录下这样一条新的undo log
你可以看到,MySQL会将对一行数据的修改undo log通过DATA_ROLL_ID指针连接在一起形成一个undo log链表链条。这样事务C如果想回滚,他会将数据回滚到事务B修改后的状态。而事务B想回滚他会将数据回滚到事务A的状态。
十二、问个问题#
在前面的文章中有专门的介绍:表空间、数据表、数据区、数据页。
表空间、数据页存在于物理层面。SQL想要修改的数据表、id=xxx的行都是逻辑上的。
而 undo log 帮你做的是逻辑上的数据回滚,而不是物理(数据页)上是数据回滚。
其实在逻辑层和物理层都能回滚。
那,你有没有想过为什么undo回滚的层面要设置在逻辑层而不是物理层的数据页级别?
原因你可以这样想:假如一个数据页中存了300行数据,而你的update语句其实可能仅仅是更新了这个数据页中的一行。但是数据库可不一定是你自己在用!很可能有其他的用户也在使用并且修改了该数据页中的另外200行。那这时如果你基于数据页层面回滚,岂不是会将别人的不想回滚的数据给改错?
十三、补充:#
在MySQL5.6、MySQL5.7版本中可以通过innodb_undo_tablespaces
参数配置redo log表空间文件的个数,但是官网也有介绍这个参数在未来的MySQL版本中将会被废弃,在MySQL8.0中初始化MySQL实例时会创建两个默认的撤消表空间,并且可以使用CREATE UNDO TABLESPACE
语法创建其他撤消表空间 。
但是不管怎么样,如果你使用的是MySQL5.7还是推荐使用这些参数以及开启undo log的自动truncate。
参考:
《MySQL技术内幕》
https://dev.mysql.com/doc/refman/5.7/en/innodb-undo-logs.html
https://dev.mysql.com/doc/refman/5.7/en/innodb-undo-tablespaces.html
https://dev.mysql.com/doc/refman/5.7/en/glossary.html#glos_undo_tablespace
推荐阅读#
- 大家常说的基数是什么?(已发布)
- 讲讲什么是慢查!如何监控?如何排查?(已发布)
- 对NotNull字段插入Null值有啥现象?(已发布)
- 能谈谈 date、datetime、time、timestamp、year的区别吗?(已发布)
- 了解数据库的查询缓存和BufferPool吗?谈谈看!(已发布)
- 你知道数据库缓冲池中的LRU-List吗?(已发布)
- 谈谈数据库缓冲池中的Free-List?(已发布)
- 谈谈数据库缓冲池中的Flush-List?(已发布)
- 了解脏页刷回磁盘的时机吗?(已发布)
- 用十一张图讲清楚,当你CRUD时BufferPool中发生了什么!以及BufferPool的优化!(已发布)
- 听说过表空间没?什么是表空间?什么是数据表?(已发布)
- 谈谈MySQL的:数据区、数据段、数据页、数据页究竟长什么样?了解数据页分裂吗?谈谈看!(已发布)
- 谈谈MySQL的行记录是什么?长啥样?(已发布)
- 了解MySQL的行溢出机制吗?(已发布)
- 说说fsync这个系统调用吧! (已发布)
- 简述undo log、truncate、以及undo log如何帮你回滚事物! (已发布)
- 我劝!这位年轻人不讲MVCC,耗子尾汁! (已发布)
- MySQL的崩溃恢复到底是怎么回事? (已发布)
- MySQL的binlog有啥用?谁写的?在哪里?怎么配置 (已发布)
- MySQL的bin log的写入机制 (已发布)