mysql更新语句怎么写 mysql更新语句( 三 )


前面我们说过了 , binlog会记录所有的逻辑操作 , 并且是采用“追加写”的形式 。如果你的DBA承诺说半个月内可以恢复 , 那么备份系统中一定会保存最近半个月的所有binlog , 同时系统会定期做整库备份 。这里的“定期”取决于系统的重要性 , 可以是一天一备 , 也可以是一周一备 。
当需要恢复到指定的某一秒时 , 比如某天下午两点发现中午十二点有一次误删表 , 需要找回数据 , 那你可以这么做:
首先 , 找到最近的一次全量备份 , 如果你运气好 , 可能就是昨天晚上的一个备份 , 从这个备份恢复到临时库;
然后 , 从备份的时间点开始 , 将备份的binlog依次取出来 , 重放到中午误删表之前的那个时刻 。
这样你的临时库就跟误删之前的线上库一样了 , 然后你可以把表数据从临时库取出来 , 按需要恢复到线上库去 。
好了 , 说完了数据恢复过程 , 我们回来说说 , 为什么日志需要“两阶段提交” 。这里不妨用反证法来进行解释 。
由于redo log和binlog是两个独立的逻辑 , 如果不用两阶段提交 , 要么就是先写完redo log再写binlog , 或者采用反过来的顺序 。我们看看这两种方式会有什么问题 。
仍然用前面的update语句来做例子 。假设当前ID=2的行 , 字段c的值是0 , 再假设执行update语句过程中在写完第一个日志后 , 第二个日志还没有写完期间发生了crash , 会出现什么情况呢?
先写redo log后写binlog 。假设在redo log写完 , binlog还没有写完的时候 , MySQL进程异常重启 。由于我们前面说过的 , redo log写完之后 , 系统即使崩溃 , 仍然能够把数据恢复回来 , 所以恢复后这一行c的值是1 。
但是由于binlog没写完就crash了 , 这时候binlog里面就没有记录这个语句 。因此 , 之后备份日志的时候 , 存起来的binlog里面就没有这条语句 。
然后你会发现 , 如果需要用这个binlog来恢复临时库的话 , 由于这个语句的binlog丢失 , 这个临时库就会少了这一次更新 , 恢复出来的这一行c的值就是0 , 与原库的值不同 。
先写binlog后写redo log 。如果在binlog写完之后crash , 由于redo log还没写 , 崩溃恢复以后这个事务无效 , 所以这一行c的值是0 。但是binlog里面已经记录了“把c从0改成1”这个日志 。所以 , 在之后用binlog来恢复的时候就多了一个事务出来 , 恢复出来的这一行c的值就是1 , 与原库的值不同 。
可以看到 , 如果不使用“两阶段提交” , 那么数据库的状态就有可能和用它的日志恢复出来的库的状态不一致 。
你可能会说 , 这个概率是不是很低 , 平时也没有什么动不动就需要恢复临时库的场景呀?
其实不是的 , 不只是误操作后需要用这个过程来恢复数据 。当你需要扩容的时候 , 也就是需要再多搭建一些备库来增加系统的读能力的时候 , 现在常见的做法也是用全量备份加上应用binlog来实现的 , 这个“不一致”就会导致你的线上出现主从数据库不一致的情况 。
【mysql更新语句怎么写 mysql更新语句】简单说 , redo log和binlog都可以用于表示事务的提交状态 , 而两阶段提交就是让这两个状态保持逻辑上的一致 。

推荐阅读