1、扫描最后一个 Binlog 文件,提取其中的 xid;
2、重做检查点以后的 redo 日志,搜集处于 prepare 阶段的事务链表,将事务的 xid 与 binlog 中的 xid 对比,若存在,则提交,否则就回滚;
总结一下,基本顶多会出现下面是几种情况:
当事务在 prepare 阶段 crash,数据库 recovery 的时候该事务未写入 Binary log 并且存储引擎未提交,将该事务 rollback。
当事务在 binlog 阶段 crash,此时日志还没有成功写入到磁盘中,启动时会 rollback 此事务。
当事务在 binlog 日志已经 fsync 到磁盘后 crash,但是 InnoDB 没有来得及 commit,此时 MySQL 数据库 recovery 的时候将会读出 binlog 中的 xid,然后告诉 InnoDB 提交这些 xid 的事务,InnoDB 提交完这些事务后会回滚其它的事务,使存储引擎和二进制日志始终保持一致。
总结起来说就是如果一个事务在 prepare 阶段中落盘成功,并在 MySQL Server 层中的 binlog 也写入成功,那这个事务必定 commit 成功。
总结介绍了 MySQL 里面最重要的两个日志,即物理日志 redo log 和逻辑日志 binlog。
redo log 用于保证 crash-safe 能力。innodb_flush_log_at_trx_commit 这个参数设置成 1 的时候,表示每次事务的 redo log 都直接持久化到磁盘。这个参数我建议你设置成 1,这样可以保证 MySQL 异常重启之后数据不丢失。
sync_binlog 这个参数设置成 1 的时候,表示每次事务的 binlog 都持久化到磁盘。这个参数我也建议你设置成 1,这样可以保证 MySQL 异常重启之后 binlog 不丢失。
我还跟你介绍了与 MySQL 日志系统密切相关的「两阶段提交」。两阶段提交是跨系统维持数据逻辑一致性时常用的一个方案,即使你不做数据库内核开发,日常开发中也有可能会用到。