MySQL 数据库的事务性(InnoDB)

只有 InnoDB 引擎才支持 MySQL 的事务(transaction)。

事务用于维护数据库的完整性,保证 SQL 语句要么全部执行,要么全部不执行。

每一条语句都是一个事务。

MySQL 事务性的特点(ACID)

  • 原子性(Atomicity,不可分割性) 一个事务中的所有操作,要么全部完成,要么全部不完成,不会结束在中间某个环节。事务在执行过程中发生错误,会被回滚(rollback)到事务开始前的状态,就像这个事务从来没有被执行过一样。
  • 一致性(Consistency) 事务开始和结束前后,数据库的完整性没有被破坏。
  • 隔离性(Isolation,又称独立性) 数据库允许多个并发事务同时对其数据进行读写和修改的能力。隔离性可以防止多个事务并发执行时由于交叉执行而导致的数据不一致。事务隔离分为不同级别,包括读未提交(Read Uncommitted)、读已提交(Read Committed)、可重复读(Repeatable Read)、串行化(Serializable)。
  • 持久性(Durability) 事务处理结束后,对数据的修改是永久的,即使系统故障也不会丢失。

如何保证 ACID

原子性的保证

MySQL 的原子性是利用 InnoDB 的 Undo Log 来实现的。

Undo Log:回滚日志。提供回滚和多个行版本控制(MVCC)。

当数据需要回滚时,使用 Undo Log 进行回滚。当 delete 一条记录时,记录一条相反的 Insert 记录;update 一条记录时,记录一条相反的 update 记录;insert 一条记录时,记录一条 delete 记录。进行 rollback 时,便可根据逻辑记录反向执行语句。

若需要行版本控制,即某一行被其他事务锁定时,它可以从 Undo Log 中分析出以前的数据是什么,从而提供该行版本信息,让用户实现非锁定一致性读取。

事务提交的时候,InnoDB 不会立即删除 Undo Log。但会将事务对应的 Undo Log 放入删除列表中,未来通过 purge 来删除。提交事务时,会判断 Undo Log 分配的页是否可以重用。如果可以,则会分配给后面来的事务,避免浪费存储空间和性能。

根据 Undo Log 记录分析 delete 和 update 操作:

  • delete 操作不会立即删除数据,而是将 delete 对象打上 flag,最终的删除操作是 purge 线程完成的。
  • update 非主键列是直接进行的。
  • update 主键列是先删除该行,再插入一行目标行。

一致性的保证

通过其他三个特性来保证一致性。为了保证一致性,才会有其他三种特性。

隔离性的保证

幻读 不可重复读 脏读 事务隔离级别
读已提交(read-committed)
可重复读(repeatable-read)
串行化(serializable)
  • 读未提交

事务 B 读数据,事务 A 修改了数据没有提交,事务 B 可以看到 A 还未修改的数据。而此时若 A 回滚,B 读到的就是脏数据。

  • 读已提交

事务 B 读数据,事务 A 修改了数据没有提交,B 读到的是 A 修改前的数据。解决了脏读。

但当事务 A 修改了数据提交后,B 再次查询,得到的数据是 A 提交后的数据,不一致。产生了不可重复读的数据。

  • 可重复读

使用了快照读的方式,通过 MVVC 机制(Undo Log),读取了事务提交前的数据。

可重复读通过以下方式解决了幻读问题:检索条件有索引时,使用 Next-Key 锁,没有索引时锁表。(Next-Key:间隙锁,其他事务不能在这个间隙插入记录)

  • 串行读

同时只能有一个事务读取数据。

持久性的保证

利用 InnoDB 的 Redo Log

Redo Log 分别内存中的日志缓冲区(Redo Log Buffer)和磁盘上的重做日志文件(Redo Log File)。前者为易失的,后者为持久的。

在事务提交时,首先要记录日志,即写入磁盘上的 Redo Log File 和 Undo Log File 进行持久化。每次写入的过程都会调用一次系统的fsync,用于将 OS Buffer 中的日志刷到磁盘上。记录 Redo Log 后才会提交事务。

一般所说的 Log File 是操作系统缓存中的 Log File,不是磁盘上的。

LSN 代表事务写入重做日志字节的总量,单位为字节。LSN 同时记录在重做日志和每个页中。数据库启动时,InnoDB 检测写入重做日志中的 LSN。如果重做日志中的 LSN 大于页上的 LSN 并且已经提交,那么数据库需要进行回复操作,将重做日志应用到页中。否则不需要。

Redo Log 是物理日志。