与查询流程不一样的是,更新流程还涉及两个重要的日志模块:redo log(重做日志) 和 binlog(归档日志)。
redo log:
如果每一次的更新操作都需要写进磁盘,然后磁盘也要找到对应的那条记录,然后再更新,整个过程IO成本、查找成本都很高。为了解决这个问题,MySQL采用了WAL技术,全称Write-Ahead Logging,它的关键点就是先写日志,再写磁盘。具体来说,当有一条记录需要更新的时候,InnoDB引擎就会先把记录写到redo log里面,并更新内存,这个时候更新就算完成了。同时InnoDB引擎会在适当的时候,将这个操作记录更新到磁盘里面,而这个更新往往是在系统比较空闲的时候做。
InnoDB的redo log是固定大小的,比如可以配置为一组4个文件,每个文件的大小是1GB,那么这块总共就可以记录4GB的操作。从头开始写,写到末尾就又回到开头循环写。
有了redo log,InnoDB就可以保证即使数据库发生异常重启,之前提交的记录都不会丢失,这个能力称为crash-safe。
binlog:
redo log是InnoDB引擎特有的日志,而Server层也有自己的日志,称为binlog(归档日志)。这两种日志有以下不同点:
1、redo log是InnoDB引擎特有的;binlog是MySQL的Server层实现的,所有的引擎都可以使用。
2、redo log是物理日志,记录的是“在某个数据页上做了什么修改”;binlog是逻辑日志,记录的是这个语句的原始逻辑。
3、redo log是循环写的,空间固定会用完;binlog是可以追加写入的。binlog文件写到一定大小后会切换到写一个,并不会覆盖以前的日志。
所以一条更新sql语句执行的流程图如下:
由于red log和binlog是两个独立的逻辑,所以采用两阶段提交。这样可以避免先后顺序提交的话,导致数据上不同步的问题,事务不一致,那么数据库的状态就有可能和用它的日志恢复出来的库的状态不一致。这样在误操作后需要用这个过程来恢复数据。当你需要扩容的时候,也就是需要再多大件一些备库来增加系统的读能力的时候,现在常见的做法也是用全量备份加上用用binlog来实现的,这个“不一致”就会导致你的线上主从数据库不一致的情况。
综上,两个阶段提交就是让这两个状态保持逻辑上的一致。