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