【mysql数据库】事务、redo日志、undo日志
一、事务
二、事务状态机
三、redo日志
(1)redo log本身由两部分所构成,即重做日志缓冲(redo log buffer)和重做日志文件(redo log file)。这样的设计同样也是为了调和内存与磁盘的速度差异。
(2)InnoDB写入磁盘的策略可以通过innodb_flush_log_at_trx_commit这个参数来控制。
- 设置为0:在提交事务时,InnoDB不会立即触发将缓存日志log buffer写到磁盘文件的操作,而是每秒触发一次缓存日志回写磁盘操作,并调用操作系统fsync刷新I/O缓存。
- 设置为1:每次事务提交时MySQL都会立即把log buffer的数据写入redo log file,并且调用操作系统fsync刷新I/O缓存(刷盘操作)。值为1时,每次事务提交都持久化一次,当然是最安全的,但是数据库性能会受影响,I/O负担重,适合对安全要求极高的交易系统场景(建议配置SSD硬盘提高I/O能力)。
- 设置为2:每次事务提交时MySQL都会把redo log buffer的数据写入redo logfile,但是flush(刷到磁盘)操作并不会同时进行,而是每秒执行一次flush(磁盘I/O缓存刷新)。注意,由于进程调度策略问题,并不能保证百分之百的“每秒”。
(3)LSN值和Checkpoint
- DB宕机后重启,InnoDB会首先去查看数据页中LSN的数值,即数据页被刷新回磁盘的LSN(LSN实际上就是InnoDB使用的一个版本标记的计数)的大小,然后去查看redo log的LSN大小。如果数据页中的LSN值大,就说明数据页领先于
- 当一个日志文件写满后,InnoDB会自动切换到另一个日志文件,但切换时会触发数据库检查点checkpoint(checkpoint所做的事就是把脏页刷新回磁盘,当DB重启恢复时只需要恢复checkpoint之后的数据即可)
3.1、redo日志格式
3.2、redo日志的页结构
3.2.1、写redo log日志的页面结构(此处叫块block,大小为512字节的页面)
3.2.2、redo log日志的写入示意(多个事务并发执行,redo log的min_transaction交叉写入)
3.2.3、redo log日志文件的整体写入示意(循环覆盖写入)
3.2.4、redo log日志内容的刷盘时机
3.2.5、redo log日志写入示意和崩溃恢复示意
-
可以被覆盖的redo log内容:buffer pool中脏页链表中的脏页被刷入磁盘后,对应的小于old_modification的redolog日志
-
崩溃恢复时redo log起点:大于等于check_point_lsn的redo log日志
-
崩溃恢复时redo log终点:从起点一直向后遍历,直到某一个redo日志页面未填充满为止(小于check_point_lsn的日志量)
-
如何恢复:(1)将redo日志的中的相同的表空间和页号进行hash,(2)将相同的页面的redo日志按生成的先后顺序组成链表 (3)依次对相同页进行回放保证数据的持久性
四、undo日志
undo log是InnoDB MVCC事务特性的重要组成部分。当我们对记录做了变更操作时就会产生undo记录。
4.1、Undo日志链(数据版本链,用于MVCC的实现)
4.1.1、数据记录的格式
4.1.2、undo日志链
4.2、删除一条记录的undo日志记录
4.2.1、事务提交前,仅做删除标记变更
4.2.2、事务提交后,移动到垃圾链表(垃圾链表的空间可被重用)
4.3、Undo日志的页面结构及页面链表
4.3.1、undo日志的页面结构(16KB大小)
4.3.2、1个事务最多有4个undo页面链表
4.3.3、不同事务之间的undo页面链表不相关
4.4、Undo日志页面链表的重用