废话不多说先来张图解释
update T set value = value+1 where ID =2
复制代码
我想可能大部分人看完这图,思考片刻,接下来的就不需要在继续看了,但是考虑到部分朋友还是新手(包括自己)以及后面复习,还是稍微唠叨一段。
update过程
首先,上图中深色背景的表示在执行器中执行,也就是Server层,浅色的是在InnoDB引擎中执行。
由于很多朋友并不是专业的DBA或者对MySQL内部原理并不是特别清晰,所以先对redolog和binlog做简单的介绍。
- redolog
重做日志,属于物理日志,上面存储的是数据库中最终的内容,有固定的大小,可以循环读写,一般设置innodb_flush_log_at_trx_commit为1,表示commit事务时将redolog上面的数据刷入到磁盘(具体的可以自行研究redolog file 和redolog buffer)。具有两个状态分别是prepare和commit,在MySQL重启恢复时会根据commit状态恢复数据。 - binlog
归档日志,属于逻辑日志,上面存储的是最初的修改逻辑可以简单的理解为sql语句,可以追加写,一般设置sync_binlog为1,表示commit事务时将binlog上面的数据刷入到磁盘进行归档。数据恢复和同步都是通过binlog来实现的。
下面以文字的方式再次描述一下update T set value = value+1 where ID =2的过程。
- 词法分析器识别出事update语句;
- 执行器去InnoDB中进行查询,找到满足ID = 2 的数据;
- 执行器将value的值加1;
- 执行器让InnoDB将刚刚的新值写入到InnoDB的内存中;
- InnoDB在redolog中加入一条记录,并把该记录的状态设置为prepare;
- 执行器经“update T set value = value+1 where ID =2” 写入到binlog中;
- 此时提交事务,将redolog中prepare的的记录状态设为commit,并且将内存中的新数据刷入磁盘。
以上就是比较简单的过程理解,那么为啥要分开写redolog呢?即传说中的两阶段提交?这里再做个简单的分析。
首先对这种方式的好处做个总结:保证以上所有的过程如果出现MySQL实例奔溃都不会导致事务的丢失或异常。
接下来分析一下这么做的具体原因:
- 如果是第5步之前crash,就是还没写任何日志,那么事务就不存在,在恢复后从redolog和binlog中都不会有任何的问题;
- 如果写完redolog 的prepare出现了crash,那么恢复时,通过redolog和binlog的对比,会发现只要一个prepare的日志,那么会将事务进行回滚,保证redolog和binlog的统一;
- 如果写完binlog后出现crash,那么恢复时,会进行根据binlog日志对redolog进行补偿,对redolog之前prepare的记录修改为commit状态,事务得到保证;
- 最后commit后crash,redolog和binlog都是正常的。
redolog只出现在InnDB中,而且是循环写的,不能持久保存,所以暂时不能用redolog来做主从或者数据备份