两阶段提交

只有bin log开启的情况下才存在,默认情况下是不存在两阶段提交的

默认情况下的流程

把事务更改的数据记录到redo log中,当事务提交时,进入commit阶段,先把redo log的状态变为

commit。然后根据innodb_flush_log_at_trx_commit有不同的行为

如果宕机了要回滚,就看看redo log状态是否为commit,如果是就数据恢复。如果是prepare,就根据

redo log的完整性,看看是否要回滚或者数据恢复

在开启了redo log和bin log的情况下就需要考虑到两个的一致性了

1.主节点宕机了,redo写了,但bin log没来得及写入,那么主节点重启数据恢复后,数据就会出现主从

不一致

2.主节点宕机,redo没写,但bin log已经写了,那么也会出现主从不一致的情况

两阶段提交就是为了解决redo log和bin log不一致的情况

它其实就是分布式事务协议,保证多个逻辑要么都成功,要么都失败

它把单个事务的提交拆成了两个阶段,一个是 prepare阶段,一个是commit阶段

prepare

    * 将XID(内部事务XA的ID)写入redo log,并将redo log的事务状态置为prepare。然后将redo log持久化到磁盘(InnoDB_flush_log_trx_id==1)

commit

    * <font style="color:rgb(44, 62, 80);">把 XID 写入到 binlog</font>,并将其持久化到磁盘 (sync==1)
    * <font style="color:rgb(44, 62, 80);">接着调用引擎层的接口,把redo log对应的事务状态置为commit,这时候不需要持久化,只需要进行write就可以了即存到os的page  cache。因为只有bin log写入成功,</font>**<font style="color:rgb(44, 62, 80);">那么不管redo log的状态是不是commit</font>**<font style="color:rgb(44, 62, 80);">,都是会认为事务已经是执行成功了的</font>

出现的异常情况

不管是时刻a or b,此时的redo log的状态都为prepare

MySQL重启后,如果发现redo log的状态为prepare,那么就会拿着redo log的XID去bin log里面寻

找,是否存在。如果存在,表示bin log已经写入成功,即事务已经执行成功了,那么就做数据恢复

如果没有,即事务没执行成功,就会做一个事务回滚操作

ps:事务回滚时redo log会怎么变化?事务回滚redo log也会产生相应数据变更记录

所以说两阶段提交是以 bin log写入成功为事务提交成功的标识

两阶段提交有什么缺点吗?

1.磁盘IO高,会刷两次盘,一次是redo,一次是binlog

2.锁竞争激烈,早期MySQL,事务只有获取锁,才能进入prepare状态,一直到commit状态才会释放

虽然加锁完美解决了一致性的问题,但在高并发的情况下性能不太行

这时候组提交就出现了