之前我们也清楚了,binlog是MySQL中Server层的日志,redo log是InnoDB存储引擎特有的。我们为了一致性就需要把这两个日志很好的持久化下来。而上面的redo log经历prepare和commit两个阶段才算提交。要解释为redo log什么需要两阶段提交,那么我们就用反证法说一说如果没有两阶段提交会发生什么问题吧?

redo log然后写binlog

如果redo log写完后,写binlog的时候,MySQL进程异常重启。但是我们redo log写入了这条更新,所以重启后这条数据依然会被修改。

但是因为binlog还没有写完就崩溃了,当我们需要用binlog来恢复临时库的时候就发现少了一次更新,这时候就会发生不一致。

先写binlog然后写redo log

如果binlog写完之后,redo log还没有写完就异常重启。那么InnoDB引擎就会判断事物无效,回滚这次操作。但是binlog里面却记录了这次操作。当我们使用binlog来恢复的时候就又多了一个事务,这时候又会数据不一致。

两阶段提交中发送异常重启如何解决?

我们了解到了为什么需要两阶段提交,接下来我们分析一下两阶段提交中发生异常需要怎么处理的情况。
image.png

我们把两阶段提交过程中会发生问题的两个时刻分别标记为时刻A和时刻B,分别来分析这两个时刻发生故障会出现的问题。

时刻A发生故障

这时候发生故障的话,redo log处于prepare阶段,此时redo log还没有提交所以崩溃恢复的时候这个事务就会回滚本次提交。因为binlog还没有写,所以恢复数据的时候也不会执行此次事务

时刻B发生了故障
如果时刻B说明redo log处于prepare阶段,并且binlog已经写完了。但是执行器调用存储引擎提交事务时候,redo log还没来记得修改为commit的时候发生崩溃。那么此时就需要分情况。

重启过后InnoDB引擎发现redo log是prepare阶段,那么就会根据自己的XID去寻找对应的binlog(XID是他们共同的数据字段)。如果binlog是完整的,这时候极有可能binlog已经被备库同步了,那么此时直接提交事务。如果binlog不是完整的,那么此时回滚事务。

看到这里不知道你会不会有一个疑惑。处于prepare状态的redo log和完整的binlog就可以崩溃恢复了,为什么还要再设计redo log的commit阶段?

我们继续用反证法,如果没有commit阶段的话。当我们写入redo log后事务提交,然后写binlog的时候写入失败发生了崩溃。但是事务已经提交了,就不能回滚了。如果允许回滚的话,提交事务和写binlog这之间其他事务也对这条记录进行修改,回滚就会覆盖其他事务的更新。
————————————————
版权声明:本文为CSDN博主「活在梦里丶」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_25448409/article/details/105376450