首先给两张图解释MySQL更新语句执行过程:
update 语句执行操作前的流程和查询语句一致,执行操作具体过程如下:
图中浅色框表示是在 InnoDB 内部执行的(我觉得是系统分配给MySQL有内存资源和磁盘资源,比如分给它有1G内存和100G磁盘空间),深色框表示是在执行器(server层)中执行的。
其中涉及两个重要日志:redo log 和 bin log。
redo log: 记录在InnoDB(特有)引擎中,也就是存储引擎部分;用来防止数据库发生crash时来不及操作未执行的sql语句而丢失要持久化的数据。也就是先按照sql语句在内存中更新数据,将更新的操作写入日志文件,后续再持久化到磁盘。----也就是所说的crash-safe。
打个比方:
客户多时,掌柜来不及在账本(数据库拥有的磁盘)上记账,先在黑板(log)上写下未来要在账本中执行的操作(同时要将该条记录更新到内存中,这样后续可以得到最新的记录,而不是读取磁盘上未更新的旧数据),等店铺打样后,再取出账本,拿出算盘,将黑板上的记录更新到账本上,更新一条记录就擦去黑板上对应的一条记录。(等不再操作数据库时,慢慢执行log中的sql语句,本次是为了将数据写入磁盘进行持久化,而不是写入内存,操作完一条就要从redo log中删除该条记录)。
bin log: 记录在server层(所有存储引擎都有)。用来恢复数据库到数日以前(误删数据之前的原始数据恢复),需要结合:全量备份(误删前某个时间节点的数据的全部备份) + 该时间节点后的bin log)
因为bin log记录的是之后数据的变化情况,所以分析操作可以还原数据之后的变化情况。
redo log 和bin log的两阶段提交(类似事务操作),如上图执行器的操作:
- 先将数据在内存中进行更新==》
- 然后redo log记录sql语句为prepare状态(此时数据库crash则该条记录不会持久化到磁盘(事务回滚),此时bin log中也没有记录数据表有改动,所以日后想恢复数据库到某个时间节点时,不会进行该sql语句的操作)===》
- 然后到server层的bin log记录数据库发生该条记录变动,之后马上将redo log的状态改为commit(事务提交),这样后续数据库crash了(且该条记录没有来得及写入磁盘),系统恢复后仍然会操作redo log中commit的sql语句(commit)保证该数据不丢失。同时,后续用bin log回溯数据库时得到的也是该sql执行后的数据(保证两份log记录的一致性)。
最后是自己总结归纳的一张记忆图:
参考文章:
https://time.geekbang.org/column/article/68633