MySQL事务


事务基础概念

1. 事务的定义

事务是数据库区别于简单文件系统的重要特性之一。事务指的是一组 SQL 操作,要么全部成功执行,要么全部失败回滚。可以将事务看作是一个不可分割的工作逻辑单元。事务的主要目的是确保数据库的数据的 ACID 特性,分别是原子性(Atomicity)、一致性(Consistency)、隔离性(Isolation)和持久性(Durability)。

2. 事务的分类

事务可以划分为以下几类:

2.1 扁平事务

扁平事务 是最简单的一种事务,也是实际生产中使用最频繁的一种。在扁平事务中,所有的操作都处于同一层次,由 BEGIN WORK 开始,由 COMMIT WORK 或者 ROLLBACK WORK 结束。在这个过程中,所有的操作在逻辑上是原子的,要么全部成功,要么全部失败回滚。

2.2 带有保存点的扁平事务

带有保存点的扁平事务 是在扁平事务的基础上增加了保存点的概念。在事务的执行过程中,可以设置保存点,在保存点之后的操作可以进行回滚,而保存点之前的操作不会回滚。在 MySQL 中通常使用 SAVEPOINT 来设置保存点。

2.3 链事务

链事务 可以看作是“带有保存点的扁平事务”的一种变种。“带有保存点的扁平事务”当发生系统崩溃时,所有的保存点都会消失,因为保存点是易失的,不是持久化的。链事务 是在提交一个事务时,不需要释放数据对象,将必要的处理上下文隐式地传给下一个要开始的事务。链事务中的回滚仅限于当前事务,即只能恢复到最近的一个保存点。对于锁的处理也是只释放当前事务所持有的锁。

2.4 嵌套事务

嵌套事务 是指在一个事务中可以包含另一个事务。在嵌套事务中,内层事务的提交或者回滚不会影响外层事务,但是外层事务的提交或者回滚会影响内层事务。“嵌套事务”和“链事务”的区别在于“嵌套事务”是在一个事务中包含另一个事务,而“链事务”是在一个事务提交后,另一个事务开始。

2.5 分布式事务

分布式事务 通常指的是一个在分布式环境下运行的扁平事务,因此需要根据数据所在的位置访问并协调网络中的不同节点。常见的分布式事务协议有 2PC、3PC、TCC、Seata 等。

3. 事务的实现

  • MySQL
    InnoDB 通过日志系统来实现事务,redo log 可以保证事务的原子性、一致性和持久性,undo log 可以保证事务的原子性和持久性。
  • Oracle
    Oracle 也是通过日志系统来实现事务,但是实现上更加复杂,并且支持回滚到任意时间点。

3.1 InnoDB 如何实现事务

MySQL 的 InnoDB 存储引擎使用 redo log 和 undo log 来保证事务的 ACID 属性。下面是 InnoDB 如何通过 Redo log 和 undo log 来实现事务的:

  • redo Log
    redo log 是重做日志。在事务提交前,先将要修改的数据页写入 redo log,如果在提交过程中发生中断,可以通过 redo log 重做事务。

redo log 由两部分组成:redo log bufferredo log file。在进行事务 commit 之前都会将事务的所有日志写入日志文件中进行持久化。
InnoDB 提供参数 innodb_flush_log_at_trx_commit 来控制 redo log 的刷盘策略。0:由 master thread 控制。1:每次提交后同步刷盘。2:每次提交后将数据写入文件系统缓存,不主动刷盘。

当事务提交(commit)时,必须先将该事务的所有日志写入到 redo log 文件中进行持久化,之后事务的 commit 才算完成。

redo log 基本上都是顺序写,在数据库正常运行时不需要对 redo log 文件进行读取操作。

  • redo log 与 binlog 的区别
  1. 来源不一样
    redo log 是在 InnoDB 存储引擎层产生的,而 bin log 是在 MySQL 数据库的上层产生的,并且 bin log 不仅仅是针对 InnoDB 存储引擎的,MySQL 数据库中的任何存储引擎对于数据库的修改都会产生 bin log。
  2. 内容格式不一样
    redo log 是物理日志,记录的是数据页的物理修改,而 bin log 是逻辑日志,记录的是 SQL 语句的逻辑修改。
  3. 记录的时机不一样
    redo log 是在事务提交前写入,bin log 是在事务提交后一次写入。
  4. 作用不一样
    redo log 用于保证事务的原子性、一致性和持久性,而 bin log 用于数据库的备份和恢复。
  • redo log 刷盘时为什么不需要通过双写机制保证数据的一致性
    因为 redo log 每次刷盘都是以 512 字节为单位进行,与磁盘扇区大小相同,因此通常不需要通过双写机制来保证数据的一致性。

  • LSN
    LSN 是 Log Sequence Number 的缩写,其代表的是日志序列号。LSN 表示事务写入 redo log 的字节总量,例如当前 lsn 为 1000,假设 T1 这个事务在此基础上在写入 100 字节的 redo log,lsn 就会变成 1100,可以把它理解为 redo log 的“时间戳”,记录了每一个日志事件发生的先后顺序。

  • LSN 的作用

  1. 崩溃恢复(Crash Recovery):当 MySQL 发生崩溃时,可以使用 Redo Log 进行恢复。LSN 允许 MySQL 知道从哪个点开始重做事务。MySQL 会扫描 Redo Log,根据 LSN 的顺序,重做所有已提交但尚未完全写入磁盘的事务,从而保证数据的一致性。
  2. 确保事务持久性:当一个事务提交时,InnoDB 会确保该事务的所有 Redo Log 记录都已写入磁盘。只有在 Redo Log 记录被成功写入磁盘后,事务才被认为已提交。LSN 确保了即使在 MySQL 崩溃后,已提交的事务也能被恢复。
  3. 实现 MVCC:与 Undo Log 结合使用,来实现 MVCC。通过 LSN,可以确定某个数据在特定时间点的版本,从而实现读写并发控制。
  • undo log
    undo log 是回滚日志,它记录了事务开始前的数据状态。在事务回滚时,可以根据 undo log 撤销之前的操作。

undo log 是逻辑日志,它在逻辑上保证了数据回滚到原始状态。例如,对于 INSERT 操作,undo log 中会记录相应的 DELETE 操作。

4. MVCC

多版本并发控制(MVCC),InnoDB 会在行记录上默认增加两个隐藏列来实现 MVCC 的基础:DB_TRX_ID(最新一次事务提交版本号)和 DB_ROLL_PTR(回滚指针)。数据行和 undo log 组成了不同版本的数据链,通过对比版本号和 undo log 日志,可以将所需的数据版本还原出来。

undo log 还会采用段的方式进行保存,在不同的段中存放 undo log page,通过这样的方式进行存储

总结

本文介绍了事务的基本概念、分类以及在 MySQL InnoDB 存储引擎中的实现方式。重点阐述了 redo log 和 undo log 在保证事务 ACID 特性中的作用,以及 LSN 的概念及其在崩溃恢复、持久性和 MVCC 中的应用。此外,还解释了 MVCC 的基本原理和实现机制。


  TOC