一条更新语句如何执行呢,他和查询语句一样吗,我们先看一张图
其实更新语句和查询语句的流程是基本一样的,但是他其中不一样的是涉及两个日志模块,也就是我们经常提到的redo log(重做日志)和binlog(归档日志)。
往往我们在开发的日常中,DBA同事经常在我们不小心误删除了某些数据,DBA同事总能帮我们找回来,其实他们也是利用这两个日志。
redo log
我们现在回忆一下以前酒馆的记账的模式,酒馆里有一个黑板,当酒店人多的时候,掌柜的就会把账临时记录在黑板上,当人少的时候在把账目记录在账本上,当然也可以直接把账目记录在账本上,但是这样就比较麻烦,还要在账本上找到对应的记录,再去修改记录。显然易见我们利用黑板效率更高一点,这里的黑板相当于我们数据库的redo log。
上面说的黑板和账本的配合就是我们常说的WAL(WriteAhead Logging)技术,先写日志,在写入磁盘.
具体来说,当我们要更新一条记录的时候,我们先把他写入redo log中,并更新内存,当InnoDb适当的时候把这个操作放到磁盘中,正如酒店空闲的时候把黑板的账目记录在账本上。
但是往往酒店的黑板是固定大小的,黑板写满了,我就不得把记录写到账本上,然后腾出新的空间,我们的redo log也是一样的,也是有有固定大小的,比如我们可以配置4个文件,每一个文件可以放置4G大小的数据,重头开始写,循环写,正如下图
check_point记录我们擦除的位置,write_pos记录我们写到的位置,一边写一边向后移动,当check_point和write_pos重合的时候,我就得把check_point向后移动。
因此有了redo log,当数据库发生异常重启,我们也能保证之前提交的记录不会丢失,当然我们理解一个概念crash-safe,就如账面酒店关门歇业几天,当开业的时候,依然可以通过账目和黑板明确账目.
binlog
我们之前看过数据库分为两个模块,存储引擎和server,上面说到的redo log日志是InnnoDB的特有日志,而server也有自己的日志,他就是binlog日志
当然我们会想到为什么有了binglog日志,还要有redo log,那是因为binglog日志是归档的作用,没有crash-safe的能力,因此使用插件的形式引入了redo log,
他们的不同点
redo log 是物理日志,记录在数据库做了什么,binlog日志是逻辑日志,记录了语句的原始逻辑
redo log是InnoDB存储引擎独有的,binglog是在server层,所有存储引擎都可以使用,
redo log是循环使用的,binLog日志是追加的
一条更新语句整体的执行流程如下
update T set c=c+1 where id =2
我们很多人疑惑为什么redo log开始的状态prepare状态,当提交完事务在改成commit,也就是我们常说的二阶段提交。
二阶段提交
为什么要使用二阶段提交呢,是为了保持两份日志的一致性,我们先回顾一下数据库如何恢复数据,我们知道binlog日志是追加的形式,我们每年或每天都会进行备份,当我需要恢复数据的时候,如下操作
这个时候就和误删出之前的数据一样了,这样可以在把需要的数据放到数据库中.
我们再来说为什么要使用二阶段提交,不如使用反证法证明一下
如果不用二阶段提交,一个日志写完,在写第二个日志,当第二个日志,没有写入,就直接crash宕机了。会有什么结果
先写redo日志,在写binlog日志,当redo写完之后,binlog没有来的及写入,此时宕机,我们之前就说过,crash之后,我们依然可以恢复到1(c+1)之后的数据
但是,binlog的这条更新记录没有写入,因此之后的备份,就会少这样的逻辑,如果要使用这个binlog日志恢复临时库的时候,数据还是之前的数据c=0的的数据,会导致与源库不一致
先写binlog,在写入redo日志,当redo还没有写入之后,宕机了,此时redo 日志还是c=0的状态,但是当binlog使用的时候,恢复出多了一个事物,就会导致与源库的不一致。
可以看出不适用二阶段提交,会导致用日志恢复出的数据库和源库不一致,当然你可能任务宕机的概率很低,其实当你需要扩容的时候,也会用到日志搭建从库,这样备份出的数据库会和主库的状态不一致.
简单来说,redo log和 binlog都可以表示事物的状态,而二阶段提交保证了两个日志的状态保持一致。
最后,我们可以设置innodb_flush_log_at_trx_commit为1,保证每次事务的redolog都持久化磁盘,保证redolog的crash-safe,保证数据不会丢失,也可以设置sync_binlog设置为1,这样保证了数据库重启之后保证binlog不会丢失.
希望此文对大家有所帮助,也希望大家持续关注转载。