在 MySQL 数据库中,自带一个日志模块 bin log(归档日志),这个日志模块所有的存储引擎都会使用,我们常常使用的 InnoDB 引擎还自带一个 redo log(重做日志);
前言
在之前的 文章 中我们可以清楚的知道,一条更新类型的sql语句执行过程是:权限校验 ==> 查询缓存 ==> 分析器 ==> 权限校验 ==> 执行器 ==> 引擎 , redo log prepare ==> bin log ==> redo log commit ,为什么需要两个模块呢?又为什么两个模块的执行顺序是这样的呢?
为什么要用两个模块?
MySQL 在很早之前是没有 InnoDB 存储引擎的(InnoDB 引擎是其他公司以插件的形式插入 MySQL 的),曾经 MySQL 的的默认存储引擎是 MyISAM ,但 MyISAM 引擎并没有 redo log 这个日志模块,就导致没有 crash-safe 的能力, bin log 只能用来做归档。InnoDB 引擎使用 redo log 来支持事务。
crash-safe 的能力是指:数据库在发生异常重启之后,之前提交的记录都不会丢失
为什么要以该顺序来使用两个模块?
首先我们做如下假设:
- 先写 redo log 直接提交,然后写 bin log,假设写完 redo log 后,机器挂了,bin log 日志没有被写入,那么机器重启后,这台机器会通过 redo log 恢复数据,但是这个时候 bingog 并没有记录该数据,后续进行机器备份的时候,就会丢失这一条数据,同时主从同步也会丢失这一条数据。(主从同步需要使用 bin log)
- 先写 bin log,然后写 redo log,假设写完了 bin log,机器异常重启了,由于没有 redo log,本机是无法恢复这一条记录的,但是 bin log 又有记录,那么和上面同样的道理,就会产生数据不一致的情况。
当引入 redo log 的 prepare 预提交状态,就可以解决这个问题。假设 redo log 进入 prepare 状态,并且 bin log 也已经写完了,此时机器故障了,这时候 MySQL 就有自己的处理机制,如下:
- 首先会判断 redo log 是不是完整的,如果是完整的就立即提交,恢复数据。
- 如果 redo log 不是完整的,还处于一个 prepare 的状态,这时候会去判断 bin log 是否完整,如果完整就将 redo log 提交,不完整就进行回滚(前面已经说过 InnoDB 是靠 redo log 来支持事务的)
这样就解决的了数据一致性问题