MySQL InnoDB存储引擎-事务篇

前言

事务是数据库区别于文件系统的重要特征。在文件系统中,如果正在写文件,但是操作系统突然崩溃了,这个文件有可能就损坏了。当然,有一些机制可以把文件恢复到某个时间点的状态。不过,如果需要保证两个文件同步,文件系统可能就显得无能为力了。例如,在更新完一个文件之后,需要更新第二个文件时,系统正好断电了,就会造成两个文件处于非同步的状态。

这正是事务引入的主要目的:事务会把数据库从一种一致状态转换为另一种一致状态。在数据库提交工作时,可以确保要么所有修改都已经保存了,要么都没有保存。

ACID

InnoDB存储引擎的事务完全符合ACID的特性,即以下四点:

  • 原子性(atomicity)
  • 一致性(consistency)
  • 隔离性(isolation)
  • 持久性(durability)

本篇主要总结一下几种特性的实现原理。

隔离性

隔离性的实现原理就是锁,因而隔离性也可以称为并发控制、锁等。事务的隔离性要求每个读写事务的对象对其他事务的操作对象能互相分离。再者,比如操作缓冲池中的 LRU 列表,删除,添加、移动 LRU 列表中的元素,为了保证一致性那么就要锁的介入。

InnoDB 使用锁为了支持对共享资源进行并发访问,提供数据的完整性和一致性。有关InnoDB锁的介绍,可以参考这篇文章:https://blog.csdn.net/qq_33724710/article/details/110270037

InnoDB的四种隔离级别

  1. Serializable(可序列化):主要用在 InnoDB 存储引擎的分布式事务。强制事务排序,串行化执行事务。不需要冲突控制。
  2. Repeatable Read(可重复读):一个事务按相同的查询条件读取以前检索过的数据,不会产生幻读(使用Next-Key Lock算法避免)。
  3. Read Committed(读已提交):事务从开始直到提交之前,所做的任何修改对其他事务都是不可见的。InnoDB 使用 MVCC 来读取数据,RC 隔离级别下,总是读取被锁定行最新的快照数据。
  4. Read Uncommitted(读未提交):事务中的修改,即使没有提交,对其他事务也都是可见的,一般没人用

InnoDB存储引擎默认支持的隔离级别是Repeatable Read,但与标准不同的是,InnoDB存储引擎在Repeatable Read事务隔离级别下,使用Next-Key Lock算法,避免了幻读的产生。这已经完全能保证事务的隔离性要求,达到了SQL标准的Serializable隔离级别。隔离级别越低,事务请求的锁就越少或持有锁的时间就越短,性能相对也就更高。

在InnoDB存储引擎中,可以使用以下命令来设置当前会话或全局的事务隔离级别:

set [global | session] transaction isolation level
{
read uncommited | read committed | repeatable read | serializable
}

原子性、一致性、持久性

原子性、一致性和持久性由数据库的 redo log 和 undo log 实现。redo log 称为重做日志,用来保证事务的原子性和持久性,恢复提交事务修改的页操作。undo log 来保证事务的一致性,undo 回滚行记录到某个特性版本及 MVCC 功能。

redo log

重做日志由重做日志缓冲(redo log buffer)和重做日志文件(redo log file)组成,前者是易失的,而后者是持久的

InnoDB存储引擎 通过 Force Log at Commit 机制来实现持久性,当 Commit 时,必须先将事务的所有日志写到重做日志文件进行持久化,待 Commit 操作完成才算完成。但当事务提交时,日志不写入重做日志文件,而是等待一个事件周期后再执行 Fsync 操作,由于并非强制在事务提交时进行一次 Fsync 操作,显然这可以提高数据库性能。重做日志是在 InnoDB 层产生的,记录的是对每个页的修改,并在事务进行中不断被写入。

redo log buffer默认2M内存大小,重复使用。在以下情况下落盘:

  • 事务提交时
  • Master Thread每1秒执行落盘
  • rede log buffer剩余空间小于1/2时刷新

undo log

用来实现事务回滚和 MVCC(多版本并发控制),这就需要 undo。

undo 是逻辑日志,只是将数据库逻辑恢复到原来的样子,但是数据结构和页本身在回滚之后可能不同。例如:用户执行 insert 10w 条数据的事务,表空间因而增大。用户执行 ROLLBACK 之后,会对插入的数据回滚,但是表空间大小不会因此收缩。

undo log同样也有缓存,也需要落盘。每个事务开始时,会申请一个新的undo log页或者使用列表中可以重用的页。事务结束后,会将undo log放入列表中,由purge线程判断是否需要删除。因为有的事务可能还需要用到这个页,比如快照读,需要读之前版本的快照,RC 隔离级别下,对于快照数据,总是读最新的一份快照数据。

恢复的的做法就是做与之前相反的操作,Insert 对应 Delete,Update 对应反向 Update 来实现原子性。InnoDB 中 MVCC 的实现就是靠 undo,RC 隔离级别下,对于快照数据,总是读最新的一份快照数据。

上一篇:简单图文版MVCC讲解


下一篇:《mysql》之undolog