文章已收录Github精选,欢迎Star:https://github.com/yehongzhi/learningSummary
前言
大家有没有想过为什么MySQL数据库可以实现主从复制,实现持久化,实现回滚的呢?其实关键在于MySQL里的三种log
,分别是:
-
binlog -
redo log -
undo log
这三种log也是面试经常会问的问题,下面我们一起来探讨一下吧。
一、binlog
binlog应该是日常中听的最多的关于mysql中的log。
那么什么是binlog呢?
binlog是用于记录数据库表结构和表数据变更的二进制日志,比如insert、update、delete、create、truncate等等操作,不会记录select、show操作,因为没有对数据本身发生变更。
binlog文件长什么样子呢?
使用mysqlbinlog
命令可以查看。
![](https://oscimg.oschina.net/oscnet/8b198c7b-c094-4385-9bb9-201d1cef6d6b.png)
会记录下每条变更的sql语句,还有执行开始时间,结束时间,事务id等等信息。
如何查看binlog是否打开,如果没打开怎么设置?
使用命令show variables like '%log_bin%';
查看binlog是否打开。
![](https://oscimg.oschina.net/oscnet/98f1740e-c28b-418d-a9e8-6024fc1a476b.png)
如果像上图一样,没有开启binlog,那怎么开启呢?
找到my.cnf
配置文件,增加下面配置(mysql版本5.7.31):
# 打开binlog
log-bin=mysql-bin
# 选择ROW(行)模式
binlog-format=ROW
修改后,重启mysql,配置生效。
执行SHOW MASTER STATUS;
可以查看当前写入的binlog文件名。
![](https://oscimg.oschina.net/oscnet/676da2da-a8b4-4c38-91e1-f006660090be.png)
binlog用来干嘛的呢?
第一,用于主从复制。一般在公司中做一主二从的结构时,就需要master节点打开binlog日志,从机订阅binlog日志的信息,因为binlog日志记录了数据库数据的变更,所以当master发生数据变更时,从机也能随着master节点的数据变更而变更,做到主从复制的效果。
![](https://oscimg.oschina.net/oscnet/2f8fd11e-88f5-4d9e-9e8b-38ed539b9cba.png)
第二,用于数据恢复。因为binlog记录了数据库的变更,所以可以用于数据恢复。我们看到上面图中有个字段叫Position,这个参数是用于记录binlog日志的指针。当我们需要恢复数据时,只要指定--start-position和--stop-position,或者指定--start-datetime和--stop-datetime,那么就可以恢复指定区间的数据。
二、redo log
假设有一条update语句:
UPDATE `user` SET `name`='刘德华' WHERE `id`='1';
我们想象一下mysql修改数据的步骤,肯定是先把id
='1'的数据查出来,然后修改名称为'刘德华'。再深层一点,mysql是使用页作为存储结构,所以MySQL会先把这条记录所在的页加载到内存中,然后对记录进行修改。但是我们都知道mysql支持持久化,最终数据都是存在于磁盘中。
假设需要修改的数据加载到内存中,并且修改成功了,但是还没来得及刷到磁盘中,这时数据库宕机了,那么这次修改成功后的数据就丢失了。
为了避免出现这种问题,MySQL引入了redo log。
![](https://oscimg.oschina.net/oscnet/e3ce14e5-e49d-44c1-8583-506265ba2b69.png)
如图所示,当执行数据变更操作时,首先把数据也加载到内存中,然后在内存中进行更新,更新完成后写入到redo log buffer中,然后由redo log buffer在写入到redo log file中。
redo log file记录着xxx页做了xxx修改,所以即使mysql发生宕机,也可以通过redo log进行数据恢复,也就是说在内存中更新成功后,即使没有刷新到磁盘中,但也不会因为宕机而导致数据丢失。
redo log与事务机制是如何配合工作的?
![](https://oscimg.oschina.net/oscnet/bc88cc49-fe52-4d95-8224-ae6556606c5d.png)
如图所示:
第1-3步骤就是把数据变更,然后写入到内存中。
第4步记录到redo log中,然后把记录置为prepare(准备)状态。
第5,6步提交事务,提交事务之后,第7步把记录状态改成commit(提交)状态。
保证了事务与redo log的一致性。
binlog和redo log都可以数据恢复,有什么区别?
redo log是恢复在内存更新后,还没来得及刷到磁盘的数据。
binlog是存储所有数据变更的情况,理论上只要记录在binlog上的数据,都可以恢复。
举个例子,假如不小心整个数据库的数据被删除了,能使用redo log文件恢复数据吗?
不可以使用redo log文件恢复,只能使用binlog文件恢复。因为redo log文件不会存储历史所有的数据的变更,当内存数据刷新到磁盘中,redo log的数据就失效了,也就是redo log文件内容是会被覆盖的。
binlog又是在什么时候记录的呢?
答,在提交事务的时候。
![](https://oscimg.oschina.net/oscnet/298e8dda-97a9-4f46-b420-fc3890a42468.png)
三、undo log
undo log的作用主要用于回滚,mysql数据库的事务的原子性就是通过undo log实现的。我们都知道原子性是指对数据库的一系列操作,要么全部成功,要么全部失败。
undo log主要存储的是数据的逻辑变化日志,比如说我们要insert
一条数据,那么undo log就会生成一条对应的delete日志。简单点说,undo log记录的是数据修改之前的数据,因为需要支持回滚。
那么当需要回滚时,只需要利用undo log的日志就可以恢复到修改前的数据。
undo log另一个作用是实现多版本控制(MVCC),undo记录中包含了记录更改前的镜像,如果更改数据的事务未提交,对于隔离级别大于等于read commit的事务而言,不应该返回更改后数据,而应该返回老版本的数据。
总结
学完之后,我们知道这三种日志在mysql中都有着重要的作用,再回顾一下:
-
binlog主要用于复制和数据恢复。 -
redo log用于恢复在内存更新后,还没来得及刷到磁盘的数据。 -
undo log用于实现回滚和多版本控制。
这篇文章就讲到这里了,感谢大家的阅读,希望看完大家能有所收获!
觉得有用就点个赞吧,你的点赞是我创作的最大动力~
我是一个努力让大家记住的程序员。我们下期再见!!!
能力有限,如果有什么错误或者不当之处,请大家批评指正,一起学习交流!
本文分享自微信公众号 - java技术爱好者(yehongzhi_java)。
如有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。