• MySQL事务,从redo log、bin log、undo log说起...


    前言

    你可能需要的内容:
    搞定数据库事务、事务的隔离级别,以及脏读、不可重复读、幻读,我是认真的_Java Punk的博客-CSDN博客通过本篇,你将掌握事务特性【ACID】,【事务隔离级别】详解和修改方法,数据库【脏读,不可重复读,幻读】。https://blog.csdn.net/weixin_44259720/article/details/112679001?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522165823539216780366557150%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fblog.%2522%257D&request_id=165823539216780366557150&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~blog~first_rank_ecpm_v1~rank_v31_ecpm-2-112679001-null-null.185^v2^control&utm_term=%E4%BA%8B%E5%8A%A1&spm=1018.2226.3001.4450

    通过本讲,你将学到redo log、bin log、undo log日志系统的产生、释放过程,作用,以及与事务(ACID)的关系。


    一、事务

    事务:一组逻辑操作单元,使数据从一种状态变换到另一种状态。

    事务处理的原则:保证所有事务都作为一个工作单元来执行,即使出现了故障,都不能改变这种执行方式。当在一个事务中执行多个操作时,要么所有的事务都被提交( commit ),那么这些修改就永久地保存下来;要么数据库管理系统将放弃所作的所有修改,整个事务回滚( rollback )到最初状态。

    1.1 事务的特性:ACID

    事务有4种特性:原子性、一致性、隔离性和持久性。

    • 原子性(atomicity):

    指事务是一个不可分割的工作单位,要么全部提交,要么全部失败回滚

    • 一致性(consistency):

    指事务执行前后数据从一个合法性状态变换到另外一个合法性状态这种状态是语义上的而不是语法上的,跟具体的业务有关。

    • 隔离型(isolation):

    指一个事务的执行不能被其他事务干扰,即一个事务内部的操作及使用的数据对并发的其他事务是隔离的,并发执行的各个事务之间不能互相干扰。

    • 持久性(durability):

    指一个事务一旦被提交,它对数据库中数据的改变就是永久性的接下来的其他操作和数据库故障不应该对其有任何影响。

    1.2 事务是如何实现的

    事务的持久性是通过事务日志来保证的,包括重做日志(redo log)和回滚日志(undo log)。

    当我们通过事务对数据进行修改的时候,首先会将数据库的变化信息记录到重做日志(redo log)中,然后再对数据库中对应的行进行修改。这样做的好处是,即使数据库系统崩溃,数据库重启后也能找到没有更新到数据库系统中的重做日志,重新执行,从而使事务具有持久性。

    而当事务需要回滚的时候,就用到了回滚日志(undo log),从而使事务具备原子性和一致性。

    简单整理下他们的关系:

    • 事务的隔离性:由【锁机制】实现;
    • 事务的原子性、一致性和持久性:由事务的 redo log和undo log日志来保证;
    • redo log: 重做日志,提供再写入操作,恢复提交事务修改的页操作,用来保证事务的持久性;
    • undo log:回滚日志,回滚行记录到某个特定版本,用来保证事务的原子性、一致性。

    二、redolog,binlog,undolog

    redo log 和 undo log 是InnoDB存储引擎层的日志,bin log 是MySQL Server层记录的日志, 两者都是记录了某些操作的日志(不是所有),自然有会些重复,但两者记录的格式不同。

    2.1 redo log

    用于记录事务操作的变化,记录的是数据修改之后的值,不管事务是否提交都会记录下来。

    作用:

    确保事务的持久性。防止在发生故障的时间点,尚有脏页未写入磁盘,在重启mysql服务的时候,根据redo log进行重做,从而达到事务的持久性这一特性。

    内容:

    redo log是物理格式的日志,记录的是物理数据页面的修改的信息,其redo log是顺序写入redo log file的物理文件中去的。

    产生:

    redo log是循环写,日志空间大小固定。

    事务开始之后就产生redo log,redo log 的落盘并不是随着事务的提交才写入的,而是在事务的执行过程中便开始写入redo log文件中。原因就是,重做日志有一个缓存区Innodb_log_buffer,Innodb_log_buffer的默认大小为8M,Innodb存储引擎先将重做日志写入innodb_log_buffer中。

    释放:

    当对应事务的脏页写入到磁盘之后,redo log的使命也就完成了,重做日志(redo log)占用的空间就可以重用(被覆盖)。

    将innodb日志缓冲区的日志刷新到磁盘的三种方式:

    1. Master Thread 每秒一次执行刷新Innodb_log_buffer到重做日志文件。
    2. 每个事务提交时会将重做日志刷新到重做日志文件。
    3. 当重做日志缓存可用空间 少于一半时,重做日志缓存被刷新到重做日志文件

    即使某个事务还没有提交,Innodb存储引擎仍然每秒会将重做日志缓存刷新到重做日志文件。这一点是必须要知道的,因为这可以很好地解释再大的事务的提交(commit)的时间也是很短暂的。


     2.2 undo log

    undo log是在事务开始之前保存的被修改数据的一个版本,产生undo日志的时候,同样会伴随类似于保护事务持久化机制的redolog的产生。

    作用:

    保存了事务发生之前的数据的一个版本,可以用于回滚,同时可以提供多版本并发控制下的读(MVCC),也即非锁定读。

    内容:

    逻辑格式的日志,在执行undo的时候,仅仅是将数据从逻辑上恢复至事务之前的状态,而不是从物理页面上操作实现的,这一点是不同于redo log的。

    undo表空间可以配置成独立的文件,但是提前需要在配置文件中配置,完成数据库初始化后生效且不可改变undo log文件的个数。如果初始化数据库之前没有进行相关配置,那么就无法配置成独立的表空间了。

    产生:

    事务开始之前,将当前是的版本生成undo log,undo 也会产生 redo 来保证undo log的可靠性。

    释放:

    当事务提交之后,undo log并不能立马被删除,而是放入待清理的链表,由purge线程判断是否由其他事务在使用undo段中表的上一个事务之前的版本信息,决定是否可以清理undo log的日志空间。


     2.3 bin log

    bin log 是MySQL Server层记录的日志,所有引擎都可以使用,这样在数据库用别的存储引擎时可以达到一致性的要求。

    作用:

    用于数据复制和数据还原。在主从复制中,从库利用主库上的binlog进行重播,实现主从同步。

    内容:

    逻辑格式的日志。包括了执行的sql语句(增删改)以及反向的信息,也就意味着delete对应着delete本身和其反向的insert;update对应着update执行前后的版本的信息;insert对应着delete和insert本身的信息。

    因此可以基于binlog做到类似于oracle的闪回功能,其实都是依赖于binlog中的日志记录。

    产生:

    binlog是追加写,是指一份写到一定大小的时候会更换下一个文件,不会覆盖。

    事务提交的时候,一次性将事务中的sql语句(一个事物可能对应多个sql语句)按照一定的格式记录到 bin log 中。这里与 redo log 很明显的差异就是 redo log 并不一定是在事务提交的时候刷新到磁盘,redo log是在事务开始之后就开始逐步写入磁盘。

    因此对于事务的提交,即便是较大的事务,提交(commit)都是很快的,但是在开启了bin_log的情况下,对于较大事务的提交,可能会变得比较慢一些。这是因为 bin log 是在事务提交的时候一次性写入的造成的。

    释放:

    bin log 的默认是保持时间由参数expire_logs_days配置,也就是说对于非活动的日志文件,在生成时间超过expire_logs_days配置的天数之后,会被自动删除。


    2.4 区别

    三种日志的区别:

    • redo log和undo log是InnoDB引擎的,binlog是MySQL Server层的;
    • redo log是物理日志,记录该数据页更新的内容;binlog是逻辑日志,记录的是这个更新语句的原始逻辑;
    • redo log是循环写,日志空间大小固定;binlog是追加写,是指一份写到一定大小的时候会更换下一个文件,不会覆盖
    • redo log记录事务执行后的状态,用来恢复未写入data file的已成功事务更新的数据;undo log用于记录事务开始前的状态,用于事务失败时的回滚操作。
    • 应用场景不同:redo log作为异常宕机或者介质故障后的数据恢复使用;binlog可以作为恢复数据使用,主从复制搭建。

    如何保证主从复制的数据一致性?(两阶段提交)

    理论上MySQL是先写redo log,再写binlog,两个日志都提交成功(刷入磁盘),事务才算真正的完成。写入redo的过程分为了prepare和commit称为二阶段提交。

    一条更新语句执行的顺序:

    连接器、分析器、优化器之后,调用操作引擎,将新行写入内存,写入redo log(状态为prepare)-> 写binlog -> redo log状态修改为commit。


    总结

    1. redo log:重做日志,属于物理日志,用于记录事务操作的变化,记录的是数据修改之后的值,不管事务是否提交都会记录下来。

      更新语句执行时,InnoDB引擎会把更新记录写到redo log日志中,然后更新内存,此时算是语句执行完了,然后在空闲的时候或者是按照设定的更新策略将redo log中的内容更新到磁盘中,关键点是先写日志,再写磁盘。

    2. undo log:回滚日志,提供回滚操作,保存了事务发生之前的数据的一个版本,可以用于回滚,同时可以提供多版本并发控制下的读(MVCC),也即非锁定读;

    3. bin log:归档日志,属于逻辑日志,是以二进制的形式记录的是这个语句的原始逻辑。

  • 相关阅读:
    Compose 动画艺术探索之动画规格
    时间序列的数据分析(五):简单预测法
    Docker从入门到放弃(1) Docker简介与安装
    NSA SELinux将在Linux 6.6中去品牌化为SELinux
    一些碎碎念以及类和对象零碎知识点补充
    区间预测 | Matlab实现QRCNN-BiGRU-Attention分位数回归卷积双向门控循环单元注意力机制时序区间预测
    小程序 多个同时选择器
    超级玛丽-c++
    【座位调整】Python 实现-附ChatGPT解析
    pandas库--DataFrame常用操作
  • 原文地址:https://blog.csdn.net/weixin_44259720/article/details/125880821