Mysql日志:二进制日志、事务日志(redo log、undo log)、快照读和当前读、共享锁和排他锁、Log Buffer

Log Buffer:

log buffer到redo log有3种方式。FS page buffer是文件系统页缓冲。

方式一:每隔1秒,log buffer到FS page buffer,FS page buffer到redo log。效率高。

方式二:每次事务提交,log buffer到FS page buffer,FS page buffer到redo log。默认方式,可靠性强。

方式三:每次事务提交,log buffer到FS page buffer;每隔1秒,FS page buffer到redo log。折中方式,推荐。

参考:MySQL各种“Buffer”之Log Buffer - 墨天轮

二进制日志

Mysql的binlog是二进制日志文件。包括日志索引文件(后缀为.index)和日志文件(后缀为.00000*)。日志索引文件记录日志文件。日志文件记录数据定义和写方式的数据操作语句。(数据定义、数据操作:参考:https://blog.csdn.net/haoranhaoshi/article/details/109804069)

参考:

MySQL的Binlog原理_击水三千里的博客-CSDN博客_数据库binlog

MySQL Binlog 介绍 - whirlys - 博客园

STATEMENT:记录每一条修改数据的 SQL 语句(减少日志量,节约 IO)。
ROW:记录哪行记录被修改了,修改成什么样子了。
MIXED:从官方文档中看到,之前的 MySQL 一直都只有基于 statement 的复制模式,直到 5.1.5 版本的 MySQL 才开始支持 row 复制。从 5.0 开始,MySQL 的复制已经解决了大量老版本中出现的无法正确复制的问题。但是由于存储过程的出现,给 MySQL Replication 又带来了更大的新挑战。另外,看到官方文档说,从 5.1.8 版本开始,MySQL 提供了除 Statement 和 Row 之外的第三种复制模式:Mixed,实际上就是前两种模式的结合。在 Mixed 模式下,MySQL 会根据执行的每一条具体的 SQL 语句来区分对待记录的日志形式,也就是在 statement 和 row 之间选择一种。新版本中的 statment 还是和以前一样,仅仅记录执行的语句。而新版本的 MySQL 中对 row 模式也被做了优化,并不是所有的修改都会以 row 模式来记录,比如遇到表结构变更的时候就会以 statement 模式来记录,如果 SQL 语句确实就是 update 或者 delete 等修改数据的语句,那么还是会记录所有行的变更。 binlog三种模式的区别(row,statement,mixed)_架构师之路的博客-CSDN博客_binlog row statement
查看 binlog 格式:
show global variables like '%binlog_format%' ;
Binlog 文件超过一定大小就会产生一个新的,查看 binlog 列表:
show binary logs;
大小(默认1G):
show variables like 'max_binlog_size' ;
查看 binlog 内容:
show binlog events in 'mysql-bin.000001' ;
用 mysqlbinlog 工具,基于时间查看 binlog:
(注意这个是 Linux 命令, 不是 SQL)
/usr/bin/mysqlbinlog --start-datetime = '2025-08-22 13:30:00' --stop-datetime = '2025-08-22 14:01:01' -d 
/var/lib/mysql/mysql-bin.000001
数据恢复:
开启binlog。
定时全量数据备份(Mysql dump( MySQL入门篇(六)之mysqldump备份和恢复 - 烟雨浮华 - 博客园),如一天一次,或一周一次。
数据丢失时可恢复到数据备份的时刻:恢复到全量备份的数据,binlog中截取全量备份时刻开始的日志进行写回。

事务日志

innodb事务日志包括undo log和redo log。

https://blog.csdn.net/bjmsb/article/details/108467720

undo log:

事务操作前会将数据操作语句记录到undo 备份到undo log中,可以供快照读。如果需回滚,就将数据拷贝回缓存里。undo log为了事务原子性。

数据库事务四大特性中有一个是原子性,具体来说就是 原子性是指对数据库的一系列操作,要么全部成功,要么全部失败,不可能出现部分成功的情况。实际上,原子性底层就是通过undo log实现的。undo log主要记录了数据的逻辑变化,比如一条INSERT语句,对应一条DELETEundo log,对于每个UPDATE语句,对应一条相反的UPDATEundo log,这样在发生错误时,就能回滚到事务之前的数据状态。同时,undo log也是MVCC(多版本并发控制)实现的关键。

根据undo buffer中的操作可以回滚。回滚过程中故障,重启数据库时执行undo log中的操作回滚。

redo log:

redo log包括两部分:一个是内存中的日志缓冲(redo log buffer,也有资料是redo buffer),另一个是磁盘上的日志文件(redo log file)。mysql每执行一条DML语句,先将记录写入redo log buffer,后续某个时间点再一次性将多个操作记录写到redo log file。这种先写日志,再写磁盘的技术就是MySQL里经常说到的WAL(Write-Ahead Logging) 技术。

如果提交过程中,发生故障。重启数据库时,会执行redo log中的操作。redo log为了事务持久性。

参考:redo log日志文件 - 知乎

  • SHOW VARIABLES LIKE 'innodb_log_files_in_group';

查看配有多少个redo log文件。

  • SHOW VARIABLES LIKE 'innodb_log_file_size';

查看每个redo log文件的大小。

  • SHOW VARIABLES LIKE 'innodb_log_group_home_dir';

查看redo log文件的目录。

  • redo log文件命名:ib_logfile数字编号。如:ib_logfile0,ib_logfile1,...
  • 多个redo log文件,在逻辑上看成是一个完整的,循环使用的文件。
  • 每个redo log文件,都分成一个个512字节的小块block。每个redo log文件的前4个block作为管理块,不会用于存储redo log记录。
  • 从逻辑上看,redo log文件是一个循环块数组,每个块512字节。

 二进制日志和redo log

 redo log不是二进制日志。虽然二进制日志中也记录了innodb表的很多操作,也能实现重做的功能,但是它们之间有很大区别。

  1. 二进制日志是在存储引擎的上层产生的,不管是什么存储引擎,对数据库进行了修改都会产生二进制日志。而redo log是innodb层产生的,只记录该存储引擎中表的修改。并且二进制日志先于redo log被记录。具体的见后文group commit小结。
  2. 二进制日志记录操作的方法是逻辑性的语句。即便它是基于行格式的记录方式,其本质也还是逻辑的SQL设置,如该行记录的每列的值是多少。而redo log是在物理格式上的日志,它记录的是数据库中每个页的修改。
  3. 二进制日志只在每次事务提交的时候一次性写入缓存中的日志"文件"(对于非事务表的操作,则是每次执行语句成功后就直接写入)。而redo log在数据准备修改前写入缓存中的redo log中,然后才对缓存中的数据执行修改操作;而且保证在发出事务提交指令时,先向缓存中的redo log写入日志,写入完成后才执行提交动作。
  4. 因为二进制日志只在提交的时候一次性写入,所以二进制日志中的记录方式和提交顺序有关,且一次提交对应一次记录。而redo log中是记录的物理页的修改,redo log文件中同一个事务可能多次记录,最后一个提交的事务记录会覆盖所有未提交的事务记录。例如事务T1,可能在redo log中记录了 T1-1,T1-2,T1-3,T1* 共4个操作,其中 T1* 表示最后提交时的日志记录,所以对应的数据页最终状态是 T1* 对应的操作结果。而且redo log是并发写入的,不同事务之间的不同版本的记录会穿插写入到redo log文件中,例如可能redo log的记录方式如下: T1-1,T1-2,T2-1,T2-2,T2*,T1-3,T1* 。
  5. 事务日志记录的是物理页的情况,它具有幂等性,因此记录日志的方式极其简练。幂等性的意思是多次操作前后状态是一样的,例如新插入一行后又删除该行,前后状态没有变化。而二进制日志记录的是所有影响数据的操作,记录的内容较多。例如插入一行记录一次,删除该行又记录一次。

redo log与binlog区别

redo logbinlog
文件大小redo log的大小是固定的。binlog可通过配置参数max_binlog_size设置每个binlog文件的大小。
实现方式redo logInnoDB引擎层实现的,并不是所有引擎都有。binlogServer层实现的,所有引擎都可以使用 binlog日志
记录方式redo log 采用循环写的方式记录,当写到结尾时,会回到开头循环写日志。binlog 通过追加的方式记录,当文件大小大于给定值后,后续的日志会记录到新的文件上
适用场景redo log适用于崩溃恢复(crash-safe)binlog适用于主从复制和数据恢复

快照读、当前读

快照读(也称普通读):SQL读取的数据是快照版本,也就是历史版本,普通的SELECT就是快照读 innodb快照读,数据的读取将由 cache(原本数据) + undo(事务修改过的数据) 两部分组成。SELECT不加锁。

当前读(也称锁定读):SQL读取的数据是最新版本。通过锁机制来保证读取的数据无法通过其他事务进行修改 UPDATE、DELETE、INSERT、SELECT … LOCK IN SHARE MODE、SELECT … FOR UPDATE都是 当前读。

对于 SERIALIZABLE 隔离级别来说,如果 autocommit 系统变量被设置为OFF,那普通读的语句会转变为锁定读,和在普通的 SELECT 语句后边加 LOCK IN SHARE MODE 达成的效果一样。

共享锁排他锁

SELECT … LOCK IN SHARE MODE加共享锁(S锁, share lock)。加了共享锁,其他事务可以再加共享锁,不能加排他锁。其他事务可以读取数据,但不能修改该数据。UPDATE、DELETE、INSERT、SELECT … FOR UPDATE加排他锁(X锁, exclusive lock)。加了排他锁,其他事务不能加锁。其他事务可以读取数据,但不能修改该数据。

关于undo log的补充:

2. 行的更新过程

下面演示下事务对某行记录的更新过程:

1. 初始数据行

F1~F6是某行列的名字,1~6是其对应的数据。后面三个隐含字段分别对应该行的事务号和回滚指针,假如这条数据是刚INSERT的,可以认为ID为1,其他两个字段为空。

2.事务1更改该行的各字段的值

当事务1更改该行的值时,会进行如下操作:

  • 用排他锁锁定该行
  • 记录redo log
  • 把该行修改前的值Copy到undo log,即上图中下面的行
  • 修改当前行的值,填写事务编号,使回滚指针指向undo log中的修改前的行

3.事务2修改该行的值

与事务1相同,此时undo log,中有有两行记录,并且通过回滚指针连在一起。

因此,如果undo log一直不删除,则会通过当前记录的回滚指针回溯到该行创建时的初始内容,所幸的时在Innodb中存在purge线程,它会查询那些比现在最老的活动事务还早的undo log,并删除它们,从而保证undo log文件不至于无限增长。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值