mysql redo log为什么有两阶段提交/为什么有prepare和commit两个状态?

mysql 数据更新流程

回答标题之前,我们要先明白数据更新的流程,这两个状态是在什么时候生成的
在mysql中数据更新的流程是:
1、执行器先从引擎中找到数据,如果在内存则直接返回,如果不在内存查询后返回
2、执行器拿到数据后,会先修改数据,然后调用引擎接口重新写入数据
3、引擎将数据更新到内存,同时写入redo log,此时处于prepare状态
4、执行器生成这个操作的binlog
5、执行器调用引擎的事务提交接口,将redo状态改成commit状态,更新完成

为什么有两个状态

我们直接提交事务,直接写入redo不可以吗,为什么要设置两阶段提交的机制呢?
这里我们逆向推导,现有这样一个更新操作,要将某表中的一个字段state从1改为0

1、如果是先写入redo,再写入binlog:
如果刚写完redo,服务崩溃了,再次重启时需要做数据恢复
因为这里redo已经写入完成了,事务已经生效,所以我们数据恢复就要恢复成事务完成后的状态,即将state恢复为0;重启服务后,因为有redo记录,数据会更新成0,但是如果这时执行了binlog的数据恢复,因为binlog是没有这条操作记录的,针对state的上一次记录是1,则会恢复为1,与我们想要恢复的值不符,也就产生了问题

2、如果是先写入binlog,再写入redo:
如果刚写完binlog,服务崩溃了,同样重启后需要做数据恢复
因为redo中没有这条操作的记录,事务没有生效,所以数据恢复是要恢复成事务开始之前的状态,即将state恢复成1;重启服务后,因为没有redo记录,系统不做事务操作,但是有binlog中‘1变成0’的记录,这时进行数据恢复,会将数据更新为0(产生了一个新的事务),与我们想要恢复的值也不同

总结

所以,通过两个状态的提交的方式,保证提交事务之后,两个日志都已经写入了,同时如果采用两阶段的方式中间如果服务发生崩溃的话:
1、redo 好没写入之前崩溃,这时binlog也还没写入,恢复数据不受影响
2、redo写好了,binlog还没写崩溃时,这是redo处于prepare状态,还没有提交,恢复时事务会回滚,binlog也还没有记录,所以不会影响
3、redo已经有了commit标识,则直接提交事务,同时因为binlog有记录,则恢复数据也不受影响
4、redo写好了,binlog写好了,但是还没有commit时崩溃了,这时会判断对应事务的binlog是否存在并完整:
(1)如果存在并完整则提交事务,这时恢复到事务提交之后的状态,因为binlog中有记录,所以恢复成功
(2)如果binlog不存在或者不完整,这时会恢复到事务提交之前的状态,因为binlog中无记录或者不完整的记录不会生效,所以恢复也成功。

QQ + 微信

原文地址:https://wu55555.blog.csdn.net/article/details/115305589