redo log与undo log
前言:
这一对难兄难弟配在一起,面试的时候聊起来不要太嗨。估计面试者直接就死在这了。对MySQL的了解越多,越发现想很清晰的聊明白这两个之间的区别和联系就越难。
本着写博客让自己更清晰的角度,还是要记录一下笔者对他们的理解的。
1.事务的特性实现
什么是事务?估计这个问题每个人的回答都不太一样。笔者简单理解为:事务是一组操作的集合,这组操作是原子性的,同时成功或同时失败,不存在中间状态。
那么事务有哪些特性呢?这个大家都可以很顺溜的回答出来:ACID
那么ACID是如何实现的呢?估计这个要干倒一大片,实际笔者也无法很清楚的回答这个问题,只能照抄书本的答案:
隔离性(I):数据库锁实现
持久性(D):redo log实现
原子性(A),一致性(C):undo log实现
2.redo log
redo log也就是重做日志文件
在我们的%MYSQL_DATA_DIR%目录下,我们可以看到会有两个名为ib_logfile0 ib_logfile1的文件,这两个文件存放的就是redo log。
1)记录内容
redo log是InnoDB存储引擎的一个专属功能,它主要记录了该存储引擎的事务日志(insert、update、delete等会产生数据变更操作的一个物理记录)。
2)redo log与二进制日志的不同?
按照之前的binlog的介绍,我们知道,binlog主要记录了数据变更操作的事务日志,那么两个都记录事务日志,究竟有何区别呢?
不同点 | 产生的存储引擎不同 | 记录内容形式不同 | 写入磁盘时间点不同 |
binlog | 任何存储引擎对数据库的更改都会产生 | 记录逻辑日志 | 事务完成后进行一次写入 |
redo log | InnoDB产生的数据库更改才会产生 | 记录页修改的物理日志 | 在事务进行中被不断写入 |
在这里说一下什么叫做页修改的物理日志?
我们都知道数据存储在磁盘上,针对InnoDB而言,最小存储格式为页,数据的修改实际修改的是磁盘上对应页的数据,那么这里的页修改的物理日志就是当发生update操作时,redo log会记录在某页的某个position发生的数据的变更,修改为何值。
3)redo log存储格式
redo log以log block的形式存储,每一个log block为512字节,格式如下:
每一个block包括header、tailer和body。
4)redo log的组成
redolog由两部分组成:log buffer(内存中的日志缓冲);redo log file(磁盘上的重做日志文件)
当发生事务操作时,相关操作会被记录到log buffer中(内存中),然后在一定时机会被刷新到磁盘上(redo log file)
5)log buffer刷新磁盘时机
* 事务提交时
* log buffer中有一半内存空间被使用时
* log checkpoint时
6)LSN
先介绍一个概念LSN:Log Sequence Number的缩写,表示当前重做日志序号,它记录的是重做日志的总量(以字节为单位)。
LSN不仅存在于redo log中,还存在每个页总,每个页的头部,存在一个叫做FIL_PAGE_LSN的值,表示该页最后刷新时LSN的大小。
7)checkpoint
本来想自己写的,但是这篇博客写的挺完美了
https://blog.csdn.net/weixin_33712987/article/details/85967332
8)如何使用redo log恢复数据
我们可以先通过命令show engine innodb status;查看一下InnoDB的状态信息
...
---
LOG
---
Log sequence number 4400601352
Log flushed up to 4400601352
Pages flushed up to 4400601352
Last checkpoint at 4400601315
0 pending log flushes, 0 pending chkp writes
15 log i/o's done, 0.09 log i/o's/second
----------------------
BUFFER POOL AND MEMORY
----------------------
Total large memory allocated 8585216
Dictionary memory allocated 1013188
Buffer pool size 512
Free buffers 256
Database pages 256
Old database pages 0
Modified db pages 0
Pending reads 0
Pending writes: LRU 0, flush list 0, single page 0
...
注意:如果没有状态信息,可以先执行一个update操作
我们重点看一下这个LOG中的几个参数:
Log sequence number: log buffer中已经写入的LSN值
Log flushed up to: 已经刷新到redo logfile的LSN值
Last checkpoint at:最近一次checkpoint时的LSN值
可以看到last checkpoint<log flushed,这样再下次MySQL服务重启的时候,就会检查这两个值,发现这两个值不相等时,则执行刷新操作,将redo logfile中的从Last checkpoint at 对应的页之后的数据重新从logfile中写入到磁盘中。
3.undo log
当事务执行失败或回滚时,我们需要使用到undo log,将数据回滚到事务开始之前的样子。
1)存放位置
undo存放在数据库内部的一个undo segment中,位于共享表空间中。
2)逻辑日志OR物理日志 ?
undo log 是逻辑日志,将数据库逻辑的恢复到原来的样子。
3)如何执行逻辑日志?
InnoDB回滚时,实际上就是执行与先前操作相反的操作。
针对insert操作,在undo log中记录一条相反的delete操作;
同理:delete操作,则记录一条insert操作;
update操作,则记录一条相反的update操作,将每列值还原回去
4)undo log实现MVCC
当读取一条数据时,若该数据已被其他数据锁定,则当前事务通过undo log查询该行记录被锁定之前的内容,依此实现MVCC。
5)undo log格式
在InnoDB中,包含两种格式:
insert undo log:指在insert操作中产生的undo log;
update undo log:在delete和update操作中产生的undo log;
6)如何实现原子性?
原子性的事务操作,这一组操作,要么全部完成,要么全部回滚,如果在执行过程中发生错误,则需要恢复到事务开始时候的状态。
undo log实现原子性的原理就是:在操作数据之前,先将数据备份到undo log(位于undo segment中),然后进行数据修改。当执行rollback时,利用undo log中的内容将数据恢复到初始状态 。
总结:
MySQL的缓存机制:
当修改数据库数据时,InnoDB先将数据从磁盘读取到内存中,修改内存中的数据拷贝(修改数据的同时将该数据的物理修改记录到redo log中;将数据被修改之前的信息记录到undo log中)。
事务提交后,将被修改的内存数据(称之为脏页)刷回到磁盘(write ahead logging)。
如果事务回滚,则将undo log中的逻辑日志信息回放,将数据恢复到初始状态;
如果此时数据库宕机,脏页还没来及刷会到磁盘,则在下次数据库启动时,会检查LSN,发现最后一个checkpoint LSN小于已经刷新到redo log file的LSN时,则从checkpoint LSN开始重新刷新数据到磁盘中(通过redo log中记录)
推荐:
发现别人写的博客都比我的好,难受。。。
https://www.cnblogs.com/better-farther-world2099/p/9290966.html
https://blog.csdn.net/weixin_33712987/article/details/85967332
推荐阅读
-
详解Java中log4j.properties配置与加载应用
-
Oracle中UNDO与REDO的区别详解
-
PHP日志LOG类定义与用法示例
-
MySQL 日志系统之 redo log 和 binlog
-
MySQL的日志(二):事务日志(redo log和undo log)
-
SpringBoot整合log4j日志与HashMap的底层原理解析
-
InnoDB On-Disk Structures(五)-- Redo Log & Undo Logs (转载)
-
MySQL主库binlog(master-log)与从库relay-log关系代码详解
-
Oracle中redo与undo的作用对比讲解
-
InnoDB undo log物理结构的初始化