Undo 日志
比如A有200块钱, B有50 块钱,现在A要给B转100块” 。
(1) 开始事务 T1 (假设T1是个事务的内部编号)
(2) A余额 = A余额 -100
(3) B余额 = B余额 + 100
(4) 提交事务 T1
会对此事务记录Undo的日志文件,记录下事务开始之前的他俩账号余额:
[开始事务 T1]
[事务T1, A原有余额,200]
[事务T1, B原有余额,50]
如果事务执行到一半挂了,数据库重启以后我就根据undo的日志文件来恢复。
例子:如果第三步还没执行完就断电了, 数据库重启以后就需要根据undo日志复原,要是系统恢复的过程中又断电了,下次重启再次恢复,此操作拥有幂等性,重复多少次都没有问题。
如何判断哪些事务需要恢复
恢复之后需要在日志文件中加上一行 [回滚事务 T1] , 这样下一次恢复就不用再考虑T1这个事务了。
[开始事务 T1]
[事务T1, A原有余额,200]
[事务T1, B原有余额,50]
[提交事务 T1]
Undo日志文件中不仅仅只有余额, 事务的开始和结束也会记录,如果我在日志文件中看到了[提交事务 T1], 或者 [回滚事务 T1], 就表示此事务已经结束,不用再去理会它了, 更不用去恢复。 如果我只看到 [开始事务 T1], 而找不到提交或回滚,那就得恢复。
日志从缓冲区写入磁盘的时机
两条规则:
1. 在最新余额写入硬盘之前, 一定要先把相关的Undo日志记录写入硬盘。 例如[事务T1, A原有余额,200] 一定要在A的新余额=100写入硬盘之前写入。
2. [提交事务 T1] 这样的Undo日志记录一定要在所有的新余额写入硬盘之后再写入。
操作 | 数据缓冲区 | Undo日志缓冲区 |
|
1 | 开始事务T1 |
开始事务T1 |
|
2 | A余额 = A余额 -100 | A新余额:100 | 事务T1,A原有余额,200 |
3 | 把undo日志缓冲区内容写入磁盘 | ps:此步骤会清空undo日志缓冲区 | |
4 | 把A新余额写入磁盘 | ||
5 | B余额 = B余额 + 100 | B新余额:150 | |
6 | 把undo日志缓冲区内容写入磁盘 | ||
7 | 把B新余额写入磁盘 | ||
8 | 提交事务T1 | 提交事务T1 | |
9 | 把undo日志缓冲区内容写入磁盘 |
情况一:
如果系统在第4步和第5步之间崩溃,A的余额写入了硬盘,但是B的还没写入, Undo日志看起来是这样的:
[开始事务 T1]
[事务T1, A原有余额,200]
由于找不到事务结束的日志, 进行恢复操作, 把A的原有余额给恢复了。
情况二:
如果是在第7步和第8步之间系统崩溃,A和B的最新余额都写入了硬盘,但是没有提交事务, 那Undo日志看起来是这样的:
[开始事务 T1]
[事务T1, 旺财原有余额,200]
[事务T1, 小强原有余额,50]
由于没有事务结束的日志,也需要进行恢复,把A和B的原有余额恢复成200和50
情况三:
如果是在第8步和第9步之间系统崩溃, A和B的最新余额都写入了硬盘也提交了事务, 但是提交事务的操作没有写入Undo 日志,Undo日志还是这样:
[开始事务 T1]
[事务T1, 旺财原有余额,200]
[事务T1, 小强原有余额,50]
由于没有事务结束的日志,需要进行恢复,把A和B原有余额恢复成200和50