再探undo log原理
一、概述
在上一篇文章中我们详细介绍了redo log日志,介绍了redo log的作用、如何实现故障恢复、刷盘策略等,如果有忘记的小伙伴可以点这里快速复习一下。
本篇文章将详细介绍undo log的原理
二、undo log的作用
如果学习过前面几篇的文章,就已经知道了undo log的作用——用于事务的回滚。为什么事务需要回滚呢?这就不得不说到事务的ACID原则了,其中的A就是事务的原子性:当一个事物对数据库进行多次更改时,在提交时要么所有的改动都成功,要么在回滚事务的时候撤销所有的更改,说得通俗一点就是一个事务中的操作要么全部成功,要么全部失败,不能说只成功了一部分。举一个大家耳熟能详的例子,甲给乙转账,简化一下这个事务,包含了减少甲的余额和增加乙的余额两个步骤,如果只成功了第一步,肯定是不被允许的!
redo log在事务运行期间会记录其的对数据库的一系列更改操作,一旦期间某个操作失败了,就会根据redo log将此事务之前的操作全部撤销,感觉就像是平时写代码经常会用的Alt + Z
的撤销功能,因此,redo log保证了事务的原子性。
三、undo log是怎么实现回滚的
我们先来想一下,事务中什么样的操作需要被撤销?
- SELECT 操作不会对数据作什么,仅仅是看了一眼,如果要撤销,其实什么都不用做
- UPDATE 操作会更新旧的数据,比如把A改成B,撤销的时候会把B又改成A
- INSERT 操作会忘表中插入新的数据,撤销的时候需要把新插入的删除掉
- DELETE 操作会删除表中的数据,撤销的时候需要把被删除的数据重新插入表中
根据上面的分析,我们会发现,undo log其实只需要关心UPDATE INSERT 和 DELETE 操作。
- 对一个UPDATE 语句,需要做的就是将数据UPDATE到原来的值;
- 对于INSERT语句,只需要对新数据执行DELETE操作即可;
- 对于DELETE操作只需要对被删除的数据执行INSERT操作;
上面这些其实就是在事物发生回滚时所做的
四、redo log日志到底记录了什么样的内容
在揭晓这个答案之前,大家可以先想一下,redo log执行撤销操作需要哪些信息?
- 需要知道操作的是那一个表,因此需要记录表ID
- 需要知道操作的数据是哪一条,因此需要记录其主键(可能是多个字段组成的联合主键)
- 需要知道要撤销什么操作,比如是更新或插入操作,因此需要一个日志类型
- 一个事务中可能存在多个操作,会产生多条redo log,回滚时需要执行属于同一个事物的全部redo log,为了标记redo log属于哪个事物,因此需要redo log日志编号,同一个事物的redo log编号相同
- redo log是保存着文件中的,所以要知道每一条redo log从哪里开始到哪里结束,因此需要有日志的开始位置和日志的结束位置
经过上面的分析,我们就可以得出redo log日志的格式了,就像下面这个图:
补充:主键部分因为可能是多个字段组成的联合主键,因此需要记录每个字段的长度是多少,以及数据是,如果你没有设置主键,MySQL也有办法,因为每条数据都以一个隐藏字段row_id
,如果你没有自己设置主键,那么row_id
将作为主键
五、总结
redo log中记录了有关如何撤销事务对聚簇索引 (以后的文章会介绍,在这里暂且当做buffer pool中的缓存页) 中最新记录的更该信息,当事务发生回滚操作时,根据redo log日志编号会取出这个事务的redo log中的信息,根据每条redo log中的表ID就可以知道要操作哪个表,再根据主键就能够确定是哪一条数据,然后再更具日志类型就可以知道要进行什么操作,如果之前那是DELETE操作,回滚时就执行INSERT操作。redo log就是这样完成了事务回滚