两阶段提交的流程
MySQL想要准备事务的时候会先写redolog、binlog分成两个阶段。
两阶段提交的第一阶段 (prepare阶段):写redo-log 并将其标记为prepare状态。
紧接着写binlog
两阶段提交的第二阶段(commit阶段):写 redo-log并将其标记为commit状态。
两阶段写日志用意
binlog默认都是不开启的状态!
也就是说,如果你根本不需要binlog带给你的特性(比如数据备份恢复、搭建MySQL主从集群),那你根本就用不着让MySQL写binlog,也用不着什么两阶段提交。
只用一个redolog就够了。无论你的数据库如何crash,redolog中记录的内容总能让你MySQL内存中的数据恢复成crash之前的状态。
所以说,两阶段提交的主要用意是:为了保证redolog和binlog数据的安全一致性。只有在这两个日志文件逻辑上高度一致了。你才能放心的使用redolog帮你将数据库中的状态恢复成crash之前的状态,使用binlog实现数据备份、恢复、以及主从复制。而两阶段提交的机制可以保证这两个日志文件的逻辑是高度一致的。没有错误、没有冲突。
总的来说,不论mysql什么时刻crash,最终是commit还是rollback完全取决于MySQL能不能判断出binlog和redolog在逻辑上是否达成了一致。只要逻辑上达成了一致就可以commit,否则只能rollback。
如何判断binlog和redolog是否达成了一致
当MySQL写完redo log并将它标记为prepare状态时,并且会在redo log中记录一个XID,它全局唯一的标识着这个事务。而当你设置sync_binlog=1
时,做完了上面第一阶段写redo log后,mysql就会对应binlog并且会直接将其刷新到磁盘中。
下图就是磁盘上的row格式的binlog记录。binlog结束的位置上也有一个XID。
只要这个XID和redo log中记录的XID是一致的,MySQL就会认为binlog和redo log逻辑上一致。就上面的场景来说就会commit,而如果仅仅是redo log中记录了XID,binlog中没有,MySQL就会RollBack
对于处于PREPARE状态的事务,存储引擎既可以提交,也可以回滚,这取决于目前该事务对应的binlog是否已经写入硬盘。这时就会读取最后一个binlog日志文件,从日志文件中找一下有没有该PREPARE事务对应的xid记录,如果有的话,就将该事务提交,否则就回滚好了。