MySQL事务日志

MySQL事务日志

      一、什么是MySQL事务?

       MySQL事务(Transaction)用于保证数据的一致性,事务是在数据库管理系统中执行的一个逻辑操作单元,它是由一组数据库操作组成的逻辑工作单元。 

       这一组操作要么全部成功,要么全部失败,不存在部分成功部分失败的情况,所有的操作共进退,因此事务是一个不可分割的逻辑单元。

       二、事务解决了什么问题?

       在原来没有事务的情况下,当多个用户同时执行对同一条数据的操作时,就会涉及到冲突问题。

       比如,如果用户A在进行修改,而此时用户B也要进行修改,那么就可能会导致数据混乱或者损坏。

       通过使用事务,可以确保数据的准确性和完整性,还可以减少数据库故障对业务系统的影响,提高了系统的可用性和稳定性。

       三、MySQL事务特性

       我们知道,MySQL事务有4个特性:隔离性、持久性、原子性、一致性。

       1.  原子性(Atomicity)

       事务是一个不可分割的操作单元,要么完全执行,要么完全不执行。如果事务中的某个操作失败,那么整个事务都将被撤销,回滚到事务开始前的状态。

       2.  一致性(Consistency)

      一致性指事务将数据库从一种状态转变为下一种一致的状态。在事务开始之前和事务结束以后,数据库的完整性约束没有被破坏。

      举个例子:用户 A 和用户 B 在银行分别有 800 元和 600 元,总共 1400 元,用户 A 给用户 B 转账 200 元,分为两个步骤,从 A 的账户扣除 200 元和对 B 的账户增加 200 元。一致性就是要求上述步骤操作后,最后的结果是用户 A 还有 600 元,用户 B 有 800 元,总共 1400 元,而不会出现用户 A 扣除了 200 元,但用户 B 未增加的情况(该情况,用户 A 和 B 均为 600 元,总共 1200 元)。

       3.  隔离性(Isolation)

      事务的执行应该与其他事务的执行相互隔离,即每个事务的操作独立于其他事务的操作。这确保了事务在并发执行时,不会相互干扰导致数据不一致或异常结果。

       4.  持久性(Durability)

      事务一旦提交,其结果就是永久性的。即使发生宕机等故障,数据库也能将数据恢复。

      四、InnoDB 引擎通过什么技术来保证事务的这四个特性的呢? 

      原子性是通过 undo log (回滚日志)来保证的;

      持久性是通过 redo log (重做日志)来保证的;

      一致性是通过 redo log (重做日志) 和 undo log(回滚日志)共同来保证的;

      隔离性是通过 MVCC(多版本并发控制) 或锁机制来保证的;

     、事务日志

     事务要保证 ACID 的完整性必须依靠事务日志做跟踪。

     至关重要的三种日志:

  •   binlog 二进制日志
  •   redo log 重做日志
  •   undo log 回滚日志

     六、redo log

     重做日志用来实现事务的持久性,即事务ACID中的D。

     1、作用

     redo通常是物理日志,记录的是页的物理修改操作,数据库崩溃则用其重做。

     2、组成

     其由两部分组成:

     1)内存中的重做日志缓冲(redo log buffer),其是易失的

     2)重做日志文件(redo log file),其是持久的

     3、如何保证事务的持久性?

     通过Force Log at Commit 机制,即当事务commit提交时,innodb引擎先将 redo log buffer 写入到 redo log file 进行持久化,待事务的commit操作完成时才算完成。这种做法也被称为 Write-Ahead Log(预先日志持久化),在持久化一个数据页之前,先将内存中相应的日志页持久化。

     4、工作流程

     1)事务开启时,事务中的操作,都会先写入存储引擎的日志缓冲。

     2)在事务提交之前,缓冲的日志都需要提前刷新到磁盘上持久化,这就常说的“日志先行”(Write- Ahead-Logging)。

     3)当事务提交之后,在Buffer Pool 中映射的数据文件才会慢慢刷新到磁盘。

     4)此时如果数据库崩溃或者宕机,那么当系统重启进行恢复时,就可以根据 redo log 中记录的日志,把数据库恢复到崩溃前的一个状态。

     5)未完成的事务,可以继续提交,也可以选择回滚,这基于恢复的策略而定。

     说明:在系统启动的时候,就已经为 redo log 分配了一块连续的存储空间,以顺序追加的方式记录 redo log,通过顺序 IO来改善性能。所有的事务共享 redo log 的存储空间,它们的 Redo Log 按语句的执行顺序,依次交替的记录在一起。

     5、持久化策略

     为了确保每次日志都能写入到重做日志文件中,在每次将 log buffer 中的日志写入日志文件的过程中都会调用一次操作系统的 fsync 操作

     6、重做日志文件写入流程

     先写重做日志文件1,当文件1被顺序写满时,会切换到重做日志文件2,再当重做日志文件2也被写满时,会再切换到重做日志文件1中,依次循环; 所以说重做日志文件是循环覆盖写入的 。

     因为重做日志是循环覆盖写入的,所以不能使用其进行整个数据库的数据恢复,它只能保证数据库宕机时的事务的完整性数据;如果想要恢复全部数据的话,只能使用 binlog 二进制日志(归档日志)进行恢复。

     注意:大家可以手动修改重做日志文件组下的文件数量,并可以指定每个重做日志文件的大小,通过下面的参数:

     1)innodb_log_file_size 指定重做日志文件的大小

     2)innodb_log_files_in_group 重做日志文件组下的文件数量

     七、undo log

     1、作用

      undo log有两个作用:提供回滚和多版本并发控制(MVCC)。

      2、工作流程

      1)逻辑日志

      undo log 和 redo log 记录物理日志不一样,它是逻辑日志,根据每行记录进行记录,因此只是将数据库逻辑得恢复到原来的样子

      undo log 是逻辑日志,可以理解为:

      当 delete 一条记录时,undo log 中会记录一条对应的 Insert 记录

      当 insert 一条记录时,undo log 中会记录一条对应的 delete 记录

      当 update 一条记录时,它记录一条对应相反的 update 记录

      2)举例

      假设有 2 个数值,分别为 A=1 和 B=2, 然后将 A 修改为 3, B 修改为 4。

      下面是事务的整个工作流程:

       步骤1.  start transaction

       步骤2.  记录 A=1 到 undo log;  

       步骤3.  Update A=3

       步骤4.  记录 A=3 到 redo log

       步骤5.  记录 B=2 到 undo log 

       步骤6.  Update B=4

       步骤7.  记录 B=4 到 redo log

       步骤8.  将 redo log 刷新到磁盘

       步骤9.  Commit

       

      在 1-8 步骤的任意一步系统宕机,事务未提交,该事务就不会对磁盘上的数据做任何影响。

      如果在 8-9 之间宕机,恢复之后可以选择回滚,也可以选择继续完成事务提交,因为此时 redo log 已经持久化。

      若在 9 之后系统岩机,内存映射中变更的数据还来不及刷回磁盘,那么系统恢复之后,可以根据 redo log 把数据刷回磁盘

      所以,redo log 其实保障的是事务的持久性,而 undo log则保障了事务的原子性。

     八、binlog

      binlog 二进制日志(归档日志),这个日志是由MySql的 server层进行维护的;不管当前MySql使用的是什么存储引擎,binlog归档日志都是支持的。

      1、作用

      1)用于复制,在主从复制中,从库利用主库上的binlog进行重播,实现主从同步。

      2)数据恢复,用于数据库的基于时间点的还原。

      2、binlog的格式

      binlog 共有三种存储格式: row, statement 和混合模式。

      1)row: 记录哪行数据被修改的

      数据记录方式比较简单,但是可能会产生大量的数据废弃日志(如 更新一个全表)。

      2)statement: 记录修改数据的 SQL ,不记录修改的数据

      记录数据的过程,日志量比较小,IO 读写少。缺点是 有些函数并不支持,为了保证能够一致性,必须还需要有一些上下文的信息。

      3)混合模式:  是以上两种模式的混合使用,MySQL 会根据执行的每一条具体的 sql 语句来区分对待记录的日志形式。

      一般的语句修改使用 statment 格式保存 binlog ,如一些函数,statement 无法完成主从复制的操作,则采用 row 格式保存 binlog。

      3、与 redo 日志的区别

      1)redo 是 Innodb 存储引擎独有的binlog 是所有引擎都可以使用的

      2)redo 是物理日志,记录的是在某个数据页上做了什么修改,binlog 是逻辑日志,记录的是这个语句的原始逻辑。

      3)redo 是循环写的,空间会用完,binlog 是可以追加写的,不会覆盖之前的日志信息。

      4)Binlog 中会记录所有的逻辑,并且采用追加写的方式

      注意:

      binlog二进制日志文件在默认情况下并没有启动,需要手动进行开启的。根据MySql的官网手册了解到,开启此日志会使性能下降1%左右,这个损失大体上是可以接受的。

 

      参考链接:

      https://cloud.tencent.com/developer/article/1780893

      https://segmentfault.com/a/1190000039715378

posted @ 2021-09-13 13:10  欢乐豆123  阅读(195)  评论(0编辑  收藏  举报