只有 InnoDB 引擎才支持 MySQL 的事务(transaction)。
事务用于维护数据库的完整性,保证 SQL 语句要么全部执行,要么全部不执行。
每一条语句都是一个事务。
MySQL 事务性的特点(ACID)
如何保证 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 操作:
一致性的保证
通过其他三个特性来保证一致性。为了保证一致性,才会有其他三种特性。
隔离性的保证
事务 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 是物理日志。