MySQL事务原子性、一致性和持久性以及回滚是如何实现的?

article/2025/8/23 19:35:57

前言

《MySQL事务详解》一文中详细讲解了事务的概念,包括ACID特性,事务并发引起的问题,事务的四种隔离级别。
在事务的四种特性中,原子性、一致性、持久性通过数据库的redo log和undo log来完成,redo log称为重做日志,用来保证事务的原子性和持久性,undo log称为回滚日志,用来保证事务的一致性。事务的隔离性通过锁机制来实现。
这篇文章主要讲解redo log和undo log实现一致性、原子性和持久性。

redo 和 undo的作用都可以视为是一种恢复操作,redo恢复提交事务时修改的页操作,而undo回滚行记录到某个特定版本。因此两者记录的内容不同,redo通常是物理日志,记录的是页的物理修改操作。undo是逻辑日志,根据每行记录进行记录。

redo log

redo log称为重做日志,用来保证事务的原子性和持久性。重做日志即innodb存储引擎产生的日志,默认在mysql/data目录下面有两个文件ib_logfile0和ib_logfile1。当MySQL的实例和介质失败的时候,Innodb存储引擎就会使用重做日志文件进行恢复,保证事务的持久性。

重做日志由两部分组成:

  • 内存中的重做日志缓冲(redo log buffer),易丢失
  • 重做日志文件(redo log file),持久的

InnoDB存储引擎首先将重做日志信息放入重做日志缓冲区中,然后按一定的频率将其刷新到重做日志文件。该缓冲区不会设置得很大,因为一般每一秒刷新一次到日志文件中。

下图显示MySQL5.6下该缓冲区默认为8M:
在这里插入图片描述

一般会在一下三种情况刷新重做日志缓冲到重做日志磁盘文件中:

  • 主线程每一秒刷新一次重做日志缓冲到重做日志磁盘文件中(同步fsync方式)
  • 每个事务提交时由innodb_flush_log_at_trx_commit参数控制,其值取0表示事务提交时不触发写磁盘,而是等待主线程每秒的刷新操作,其值取1(默认值)表示同步写磁盘,其值取2表示异步写磁盘,即不能保证commit时一定会刷新重做日志缓冲到重做日志磁盘文件中,只是有这个动作发生

innodb_flush_log_at_trx_commit对事物提交性能的影响

由于innodb_flush_log_at_trx_commit默认值为1,所以默认情况下,当事务commit时,必须先将该事务的所有日志从重做日志缓冲中同步写入到重做日志文件进行持久化,该事物的commit操作才算完成。重做日志文件没有使用O_DIRECT选项,因此重做日志先写入文件系统缓存。为了确保重做日志写入磁盘,必须进行一次fsync操作,该操作的效率取决于磁盘的新能,进而影响了数据库的性能。

  • O_DIRECT: 任何读写操作都只在用户态地址空间和磁盘之间传送而不经过page cache。
  • O_SYNC: 只影响写操作,block当前写进程,先从用户态内存写入page cache, 再从page cache写入磁盘,然后才返回到用户进程。

下面比较innodb_flush_log_at_trx_commit对事物提交性能的影响:

先创建表t1和存储过程p_load:
在这里插入图片描述
在innodb_flush_log_at_trx_commit参数为1的情况下,执行命令CALL p_load(50 000),即向表t1插入50万行记录,并执行50万次fsync操作,所需时间接近2分钟:
在这里插入图片描述
在innodb_flush_log_at_trx_commit参数为0的情况下,所需时间大概为13秒:
在这里插入图片描述
innodb_flush_log_at_trx_commit设置不同值对于插入速度的影响:
在这里插入图片描述
因此,为了提高事务的提交性能,应该将大批量的数据放在事务中一次性commit,而且还有个好处是还可以使事务回滚时回到最开始的状态。

log block

在InnoDB存储引擎中,重做日志是以512字节(也是一个扇区的大小)进行存储的。这意味着重做日志缓存、重做日志文件都是以块的方式进行保存的,称之为重做日志块,每块的大小为512字节。若一个页中产生的重做日志数量大于512字节,则需要分割为多个重做日志块进程存储。

undo log

重做日志记录了事务的行为,可以很好的通过其对页进行“重做”操作,但是事务有时还需要回滚操作,这是就需要undo,将数据回滚到修改之前的样子。redo通常是物理日志,记录的是页的物理修改操作。undo是逻辑日志,根据每行记录进行记录。
上面说过redo存放子重做日志文件中,默认在mysql/data目录下面的两个文件ib_logfile0和ib_logfile1中。而undo存放在数据库内部的一个特殊段中,这个段称为undo段。

一个事务在修改当前一个页中某几条记录,同时还可能存在别的事务在对同一个页中另几条记录进行修改,因此,不能将一个页回滚到事务开始的样子,因为这样会影响到其他事务正在进行的工作。

undo log如何实现回滚?

用户执行了一个INSERT 10W条记录的数据,这个事务会导致分配一个新的段,即表空间会增大,但是事务ROLLBACK时,只是将插入操作的事务进行回滚,并没有缩减表的大小。因此,事务回滚实际做的是和之前相反的工作。对于INSERT,INSERT,对于DELETE,InnoDB存储引擎会完成一个INSERT操作,对于UPDATE,InnoDB存储引擎会完成一个相反的UPDATE操作。

这就实现了InnoDB存储引擎的回滚机制。

undo log的另一个作用

undo log的另一个作用是实现MVCC(多版本并发控制)。当用户读取被其他事务占用的记录时,可以通过undo读取之前的版本信息(即快照读),以此实现非锁定读。

此外,undo log会产生redo log,因为undo log也需要被记录下来,需要持久性的保护。


http://chatgpt.dhexx.cn/article/HSdsU7Qo.shtml

相关文章

InnoDB引擎--事务持久性

事务是指构成单一逻辑工作单元的操作的集合。数据库系统维护事务的ACID四个特性: 原子性:事务的所有操作在数据库中要么全部反映,要么全部不反映。一致性:事务执行前后数据库保持约束一致性和业务逻辑一致性。隔离性:在事务并发执行时,各个事务都感觉不到其他事务的存在。…

MySQL 是如何保证一致性、原子性和持久性的!

编辑:业余草 来源:https://www.xttblog.com/?p4891 今天,我们来简单的看一下 MySQL 的一致性、原子性和持久性问题。后面还扩展了 15 个简单的面试题,希望大家喜欢! 1、Mysql怎么保证一致性的? OK&#xf…

MySQL InnoDB 存储引擎写入磁盘(落盘)的原理\MySQL怎么保证持久性、原子性?(MySQL中是如何实现事务提交和回滚的)\隔离性

文章目录 一、MySQL InnoDB 存储引擎写入磁盘(落盘)的原理一条 update 语句在写入磁盘的过程为什么必须有“两阶段提交”呢? binlog 的写入机制 二、MySQL怎么保证持久性、原子性?(MySQL中是如何实现事务提交和回滚的)redo log(重做日志) 如…

MySQL日志(undo log 和 redo log 实现事务的原子性/持久性/一致性)

日志的重要性 日志绝对是数据库的核心. 持久化的日志记录了各种重要的信息.数据的恢复需要依赖日志。 慢查询sql语句需要用到慢查询日志。以及错误日志中保存着mysqld数据库服务端在启动过程中发生的重大错误信息... 数据库重要组成 本质上来说是一个文件系统 (两大重要组…

MySQL究竟是如何做到持久性的?

前言 我们学习事务中,对于持久性(durability)是这样定义的:事务一旦提交,则其所有的修改将会保存到数据库当做。即使此时系统崩溃,修改的数据也不会丢失。同时数据库连接中,默认有一个参数auto…

理解事务四大特性(Transaction)——原子性、一致性、隔离性和持久性(ACID)

事务是指对系统进行的一组操作,为了保证系统的完整性,事务需要具有ACID特性,具体如下: 1. 原子性(Atomic) 原子性是指事务是一个不可分割的工作单位,事务中的操作要么都发生,要么都…

持久性连接和非持久性连接

HTTP连接有两种,一种为持久性连接;另一种为非持久性连接。 由于不同的HTTP版本,使用不同的方式。 在这里分析一下二者的区别: 一、非持久性连接(Nonpersistent HTTP) 特点:每个TCP连接最多允许传输一个对象 HTTP 1.0使用的非持久性连接 过程: 响应时间分析与建…

mysql事务如何保证持久性_详解MySQL事务持久性实现

所谓MySQL事务持久性就是事务一旦提交,就是永久性的,不会因为宕机等故障导致数据丢失(外力影响不保证,比如磁盘损害)。持久性是保证了MySQL数据库的高可靠性(High Reliability),而不是高可用性(Hign Availability)。 MySQL的innoDB存储引擎,使用Redo log保证了事务的持久性…

Mysql持久性的实现

1、持久性的定义 事务一旦提交,则其所有的修改将会保存到数据库当中。即使此时系统崩溃,修改的数据也不会丢失。同时数据库连接中,默认有一个参数autocommit1(如果想要关掉,要set autocommit0,然后要手动的开启关闭&a…

数据库事务-持久性原理

持久性(Durability): 事务处理结束后,对数据的修改就是永久的,即便系统故障也不会丢失。(持久性由redo log日志来保证) 以一个跟新语句执行流为例: 在存储引擎执行时,会先在缓存池…

MYSQL 1251

今天折腾mysql,,一直在连接的时候出现1251的报错,然后百度了很多方法,都没有办法成功,,最后折腾了好久,,终于成功了,进入MySQL 8.0 Command Line Clien,依次输…

java_1125

1。从键盘输入一个字符串 编写一个程序,判断输出一个字符串中大写英文字母数,和小写英文字母数,和其他非英文字母数 2. 编写一个方法,返回一个double类型的二维数组,数组中的元素通过解析字符串参数获得&#xff0c…

java_1115

定义一个接口 MediaPlayer,表示家庭影院的一个设备。MediaPlayer 中 包含 play(),stop(), open()三个方法,分别表示播放、停止和开仓功能。 MediaPlayer 有三个实现类,分别为: DVDPlayer,表示 …

java--Integer的128陷阱

包装类 提到128陷阱就不得先说一下包装类 1.为什么有包装类 在面向对象中,“一切皆对象”,但基本数据类型的数据不太符合这一理念,基本数据类型不是对象.涉及到类型之间的转化,数据类型之间的基本操作;如果都有我们…

P1152 java

package suanfa_xiaoqiang1; import java.util.Arrays; import java.util.Scanner; public class P1152 { public static void main(String[] args) { Scanner sc new Scanner(System.in); int nsc.nextInt(); int[] anew int[n1]; //数组遍历从1开始的时候,要加…

Java(11)

学习来源:日撸 Java 三百行(21-30天,树与二叉树) 第 28 天: Huffman 编码 (节点定义与文件读取) 输入:输入表示文本文件的字符串paraFilename 输出:构造对象tempHuffman并输出文本文件的内容inputText 优…

Java-1110

https://github.com/Lannister-never-pay/JavaWebLearning/tree/main/java1108 因为懒&#xff0c;还是用的1108的module JSP 指令 作用&#xff1a;用于配置JSP页面&#xff0c;导入资源文件 格式&#xff1a;<% 指令名称 属性名1属性值1 属性名2属性值2 %> 多个键值…

Java——详解Integer128陷阱

今天我们来一起探讨一下Java的128陷阱 首先我们通过代码对128陷阱进行一个认知 public static void main(String[] args){Integer a 127 ;Integer b 127 ;Integer c 128 ;Integer d 128 ;Integer e 1000 ;Integer f 1000 ;int a1 127;int b1 127;int c1 128;int d1 …

Java-11

学习来源&#xff1a;日撸 Java 三百行&#xff08;31-40天&#xff0c;图&#xff09;_闵帆的博客-CSDN博客 36 邻接表 36.1 相当于图的压缩存储. 每一行数据用一个单链表存储。 36.2 重写了广度优先遍历. 可以发现, 使用队列的机制不变. 仅仅是把其中的 for 循环换成了 wh…

JAVA101-135

JAVA101-150 字符串StringBuilder链式编程简化代码对应的关系可以使用查表法&#xff0c;通过数组的对应的下表来改变成相应的值 修改字符串字符串变整数重点&#xff1a;字符串变为数组 ArrayList集合的基本使用集合一开始的长度为0&#xff0c;如果用循环&#xff0c;进不去 …