文本已收录至个人GitHub精选文章,欢迎Star: https://github.com/ZhongFuCheng3y/3y
在前一阵子,大哥问过我:”你知道MySQL的原子性是怎么保证的吗“。我懵逼了,MySQL怎么保证原子性?我不会啊。html
谁都知道在事务里边原子性的意思:”一个事务包含多个操做,这些操做要么所有执行,要么全都不执行“java
因而大哥就给我讲:”用的就是 undo log
啊“。git
我:”卧槽,又是知识盲区“github
后来在网上翻了一下,MySQL里边还有几种常见的log
,分别为:面试
undo log
binlog
redo log
若是你也不曾关注过这些log
,麻烦在评论区给我留个言,让我以为不是只有我一我的这么菜,行不行?sql
后来我又去搜了一下,其实这几种log在面试的时候也常常会问到,这篇文章以最简单的方式来说讲,但愿对你们有帮助。数据库
binlog
其实在平常的开发中是听得不少的,由于不少时候数据的更新就依赖着binlog
。服务器
举个很简单的例子:咱们的数据是保存在数据库里边的嘛,如今咱们对某个商品的某个字段的内容改了(数据库变动),而用户检索的出来数据是走搜索引擎的。为了让用户能搜到最新的数据,咱们须要把引擎的数据也改掉。工具
一句话:数据库的变动,搜索引擎的数据也须要变动。学习
因而,咱们就会监听binlog
的变动,若是binlog
有变动了,那咱们就须要将变动写到对应的数据源。
什么是
binlog
?
binlog
记录了数据库表结构和表数据变动,好比update/delete/insert/truncate/create
。它不会记录select
(由于这没有对表没有进行变动)
binlog
长什么样?
binlog
咱们能够简单理解为:存储着每条变动的SQL
语句(固然从下面的图看来看,不止SQL,还有XID「事务Id」等等)
binlog
通常用来作什么
主要有两个做用:复制和恢复数据
binlog
来实现的binlog
来对数据进行恢复。由于binlog
记录了数据库表的变动,因此咱们能够用binlog
进行复制(主从复制)和恢复数据。
假设咱们有一条sql语句:
update user_table set name='java3y' where id = '3'
MySQL执行这条SQL语句,确定是先把id=3
的这条记录查出来,而后将name
字段给改掉。这没问题吧?
实际上Mysql的基本存储结构是页(记录都存在页里边),因此MySQL是先把这条记录所在的页找到,而后把该页加载到内存中,将对应记录进行修改。
如今就可能存在一个问题:若是在内存中把数据改了,还没来得及落磁盘,而此时的数据库挂了怎么办?显然此次更改就丢了。
若是每一个请求都须要将数据立马落磁盘以后,那速度会很慢,MySQL可能也顶不住。因此MySQL是怎么作的呢?
MySQL引入了redo log
,内存写完了,而后会写一份redo log
,这份redo log
记载着此次在某个页上作了什么修改。
其实写redo log
的时候,也会有buffer
,是先写buffer
,再真正落到磁盘中的。至于从buffer
何时落磁盘,会有配置供咱们配置。
写redo log
也是须要写磁盘的,但它的好处就是顺序IO
(咱们都知道顺序IO比随机IO快很是多)。
因此,redo log
的存在为了:当咱们修改的时候,写完内存了,但数据还没真正写到磁盘的时候。此时咱们的数据库挂了,咱们能够根据redo log
来对数据进行恢复。由于redo log
是顺序IO,因此写入的速度很快,而且redo log
记载的是物理变化(xxxx页作了xxx修改),文件的体积很小,恢复速度很快。
看到这里,你可能会想:binlog
和redo log
这俩也太像了吧,都是用做”恢复“的。
其实他俩除了"恢复"这块是类似的,不少都不同,下面看我列一下。
binlog
记载的是update/delete/insert
这样的SQL语句,而redo log
记载的是物理修改的内容(xxxx页修改了xxx)。
因此在搜索资料的时候会有这样的说法:redo log
记录的是数据的物理变化,binlog
记录的是数据的逻辑变化
redo log
的做用是为持久化而生的。写完内存,若是数据库挂了,那咱们能够经过redo log
来恢复内存还没来得及刷到磁盘的数据,将redo log
加载到内存里边,那内存就能恢复到挂掉以前的数据了。
binlog
的做用是复制和恢复而生的。
binlog
来同步数据。binlog
存储着全部的数据变动状况,那么能够经过binlog
来对数据进行恢复。又看到这里,你会想:”若是整个数据库的数据都被删除了,那我能够用redo log
的记录来恢复吗?“不能
由于功能的不一样,redo log
存储的是物理数据的变动,若是咱们内存的数据已经刷到了磁盘了,那redo log
的数据就无效了。因此redo log
不会存储着历史全部数据的变动,文件的内容会被覆盖的。
redo log
是MySQL的InnoDB引擎所产生的。
binlog
不管MySQL用什么引擎,都会有的。
InnoDB是有事务的,事务的四大特性之一:持久性就是靠redo log
来实现的(若是写入内存成功,但数据还没真正刷到磁盘,若是此时的数据库挂了,咱们能够靠redo log
来恢复内存的数据,这就实现了持久性)。
上面也提到,在修改的数据的时候,binlog
会记载着变动的类容,redo log
也会记载着变动的内容。(只不过一个存储的是物理变化,一个存储的是逻辑变化)。那他们的写入顺序是什么样的呢?
redo log
事务开始的时候,就开始记录每次的变动信息,而binlog
是在事务提交的时候才记录。
因而新有的问题又出现了:我写其中的某一个log
,失败了,那会怎么办?如今咱们的前提是先写redo log
,再写binlog
,咱们来看看:
redo log
失败了,那咱们就认为此次事务有问题,回滚,再也不写binlog
。redo log
成功了,写binlog
,写binlog
写一半了,但失败了怎么办?咱们仍是会对此次的事务回滚,将无效的binlog
给删除(由于binlog
会影响从库的数据,因此须要作删除操做)redo log
和binlog
都成功了,那此次算是事务才会真正成功。简单来讲:MySQL须要保证redo log
和binlog
的数据是一致的,若是不一致,那就乱套了。
redo log
写失败了,而binlog
写成功了。那假设内存的数据还没来得及落磁盘,机器就挂掉了。那主从服务器的数据就不一致了。(从服务器经过binlog
获得最新的数据,而主服务器因为redo log
没有记载,无法恢复数据)redo log
写成功了,而binlog
写失败了。那从服务器就拿不到最新的数据了。MySQL经过两阶段提交来保证redo log
和binlog
的数据是一致的。
过程:
redo log
写盘,InnoDB 事务进入 prepare
状态binlog
写盘,InooDB 事务进入 commit
状态binlog
的末尾,会记录一个 XID event
,标志着事务是否提交成功,也就是说,恢复过程当中,binlog
最后一个 XID event 以后的内容都应该被 purge。
undo log
有什么用?
undo log
主要有两个做用:回滚和多版本控制(MVCC)
在数据修改的时候,不只记录了redo log
,还记录undo log
,若是由于某些缘由致使事务失败或回滚了,能够用undo log
进行回滚
undo log
主要存储的也是逻辑日志,好比咱们要insert
一条数据了,那undo log
会记录的一条对应的delete
日志。咱们要update
一条记录时,它会记录一条对应相反的update记录。
这也应该容易理解,毕竟回滚嘛,跟须要修改的操做相反就好,这样就能达到回滚的目的。由于支持回滚操做,因此咱们就能保证:“一个事务包含多个操做,这些操做要么所有执行,要么全都不执行”。【原子性】
由于undo log
存储着修改以前的数据,至关于一个前版本,MVCC实现的是读写不阻塞,读的时候只要返回前一个版本的数据就好了。
这篇文章把binlog
/redo log
/undo log
最核心的知识给讲了,还有一些细节性的东西能够自行去补充(好比binlog
有几种的模式,以及文章提到的刷盘策略等等)
若是以为学到了,请给我个赞行不行。
参考资料:
若是你们想要实时关注我更新的文章以及分享的干货的话,能够关注个人公众号「Java3y」。
在公众号下回复「888」便可获取!!
本已收录至个人GitHub精选文章,欢迎Star: https://github.com/ZhongFuCheng3y/3y求点赞 求关注️ 求分享👥 求留言💬 对我来讲真的 很是有用!!!