MySQL更新数据时,日志(redo log、binlog)执行流程

1.背景

项目需要做ES和数据库的同步,而手动在代码中进行数据同步又是ES的一些不必要的数据同步操作和业务逻辑耦合,所以使用的是读取mysql的binlog日志的方式将数据库数据同步到ES。

问题1:根据binlog同步数据的时候会不会出现业务逻辑利用事务操作数据的时候,当事务还没有提交的时候,是否能够读到binlog,也就是binlog的写入时机(是事务提交的之前写,还是事务提交后写)。
问题2:如果事务提交之前写入binlog,那么事务提交之前,事务回滚,那么binlog又会出现什么情况?

首先我们做一下实验(前提是必须要打开binlog),SQL初始化语句(下面语句全部执行

create table user
(
    id bigint not null auto_increment primary key,
    name varchar(64) null,
    status tinyint(1)  null
);
insert into user (name,status)values ('张三',1);
set autocommit = 0;

2.事务对binlog的影响

2.1:事务提交对binlog的影响

我们先确定一下MySQL执行更新SQL语句,在执行commit命令前后,binlog会有什么变化。

然后我们先使用 show master status 看一下binlog的位置(Position字段)

show master status;

然后我们执行一下更新语句:

update user set status = status + 1;

再次使用 show master status 查看发现Position并没有变。

但是,执行commit命令之后,发现Position由141169 变为 141506,说明只有事务提交之后binlog才被写入到磁盘,从库只有在主库提交之后才能读到主库写入的binlog日志。

2.2:事务回滚对binlog的影响

我们再确定一下MySQL执行更新SQL语句之后,执行rollback命令前后,binlog会有什么变化。

然后我们先使用 show master status 看一下binlog的位置

然后我们执行一下更新语句

update user set status = status + 1;

再次使用 show master status 查看发现Position并没有变,执行rollback命令之后,发现Position仍然没有变化,说明事务回滚之后binlog并不会写入磁盘。

难道binlog是在事务提交之后才写入磁盘的嘛?确实是这样的

那redo log 又是什么时候写入磁盘的呢?有上面的问题又引发一系列的问题,带着这些问题,我们来进行mysql日志的深入学习。 

3:MySQL更新数据的执行流程

首先我们要先了解一下当我们做一条数据的更新操作的时候,数据库的底层到底是如何执行的?

MySQL更新数据执行流程:

  1. 判断数据页是否在内存中(innodb Buffer pool),若为否,则从磁盘读取数据到内存中,返回数据行
  2. 若是数据页在内存中,则直接返回数据行
  3. 执行数据更新操作
  4. 数据写入内存(innodb buffer pool),同时redolog写入到内存(redo log buffer),binlog写入内存(binlog log buffer)。
  5. 执行commit操作(此commit是SQL命令操作,而不是数据的commit状态)
  6. 执行commit命令之后,则进行两阶段提交操作。
  7. 写入内存中的redolog到磁盘中(fsync操作),此时redolog处于prepare状态
  8. 写入binlog到磁盘
  9. 提交事务(buffer pool里的更新数据也会写入到表中),此时事务处于commit状态,将redo log里这个事务的相关记录状态置为commit状态。
  10. 结束。

注:以上操作为参数innodb_flush_log_at_trx_commit  (redo log)为1和sync_binlog (binlog)为1的时候。

对应MySQL的更新语句执行流程图,如图1-1。

redo log:被称之为重做日志,是在数据库发生意外时(提交失败),进行数据恢复(保证事务的一致性),redo log会备份事务执行过程中的修改数据。
binlog: 被称为归档日志,是一个二进制格式的文件,用于记录用户对数据库更新的SQL语句信息,格式分为(statement、row、mixed)
redo log 和binlog的差异如下表:

redo logbinlog
InnoDB引擎MySQL Serve
物理日志逻辑日志
循环写入追加写入

MySQL执行commit命令之后是使用两阶段提交的办法来保证事物的原子行的,至于为什么使用

两阶段提交,而不是其他的提交方式,由于篇幅有限,不做多余解释,请参考自行查询资料。

两阶段提交保证了redo log和binlog的一致性。

到目前为止,关于上面binlog的问题也就迎刃而解了,

  • 对于问题一:MySQL在事务提交之前会写入redo log和binlog到内存缓存中,在执行commit命令之后进行两阶段提交操作,将redo log和binlog写入磁盘,因此在事务提交之前不能读取到binlog日志(前提binlog没有进行被动刷盘),当然也不能看到redo log。
  • 对于问题二:binlog是在执行commit命令之后进行的刷盘,但是是在事务变成commit状态之前写入的磁盘。根据上面的实验可以看出,事务回滚对于binlog并没有什么影响(还在缓存中)。
  • 小结:执行更新数据,数据到内存(buffer pool)之后,就会写入redo log和binlog到 缓存中(redo log buffer和binlog buffer中),当执行了commit命令之后,进行两阶段提交操作:将redo log(prepare状态)和binlog写入磁盘操作,这2步算是第1阶段(预提交);没问题的话进行第2阶段,提交事务,修改事务状态为commit状态,并且将redo log状态设置为commit状态

为什么要先将redo log和binlog写入磁盘?因为是顺序读写,速度很快,而将数据写入到表中是随机读写,速度慢。

关于MySQL的日志刷盘机制是由参数innodb_flush_log_at_trx_commit 和sync_binlog控制的,具体请参考下一篇文章。

4:commit命令和commit状态区别解释

我们上面说的commit命令是指MySQL语法中的commit命令,用于提交事务,一般跟 begin/start transaction 配对使用。
而我们上图中用到的这个“commit 步骤”,指的是事务提交过程中的一个小步骤,也是最后一步。当这个步骤执行完成后,这个事务就提交完成了。
“commit 命令”执行的时候,会包含“commit 步骤”。 

  • 3
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
MySQL中的Redo LogBinlog和Undo Log是三种不同的日志类型,用于支持数据库事务的持久性、复制和回滚操作。 1. Redo Log(重做日志): Redo LogMySQL引擎内部使用的一种日志,记录了所有已提交的修改操作,以保证数据库在发生崩溃等异常情况下能够进行恢复。当数据库发生崩溃,可以通过Redo Log来重放这些修改操作,使数据库恢复到崩溃前的状态。Redo Log是在InnoDB存储引擎中实现的,通常以磁盘文件形式存在,可被视为一种类似于事务日志的机制。 2. Binlog(二进制日志): BinlogMySQL数据库服务器层产生的一种日志,用于记录数据库中所有的修改操作,包括数据修改和数据定义语句(DDL)。与Redo Log不同,Binlog记录的是逻辑操作而不是物理操作,以提供对数据的逻辑复制和恢复能力。Binlog通常以二进制文件的形式存在,并且可以被用于主从复制和数据恢复等任务。 3. Undo Log(回滚日志): Undo Log是用于支持事务回滚操作的一种日志。当一个事务执行修改操作,旧值会被记录在Undo Log中,以便于回滚操作能够恢复到之前的状态。Undo Log通常与事务的隔离级别和并发控制有关,主要用于MVCC(多版本并发控制)的实现。 这三种日志MySQL中扮演了不同角色,分别用于保证数据的持久性、支持复制和提供事务回滚功能。在数据库的正常运行和异常恢复中起到至关重要的作用。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值