MySQL事务需要的满足的ACID原则,其中的I(隔离性,Isolation)
在文章MySQL事务详解(二):隔离级别的实现MVCC和MySQL事务详解(三):脏写与幻读的绝路—锁已经详细学习过,通过MySQL的MVCC机制与锁机制来实现。
其中的C(一致性,Consistency)
的实现依靠数据库自身设定的规定和约束、程序员的业务代码实现来保证。
同时隔离性与原子性也是实现了一致性的一种手段。一致性是我们追求的最终的结果。
而A(原子性,Atomicity)
依靠MySQL的undo来保证,D(持久性,Durability)
使用MySQL的redo来保障。
这篇文章我们先来学习下undo,redo在下次分享中再详细论述。
undo的场景与作用
原子性要保证事务中的操作要么全做,要么全不做
。但是事务的执行过程中,会遇到各种场景,导致事务中断:
• 执行过程中遇到
系统故障
、服务器故障
、断电
等不可控场景• 执行过程中手动
执行了rollback语句
,提前结束事务
上述场景中,事务可能执行了增删改操作,修改了记录,为了保证原子性,需要将修改的记录改回到原来的状态,使得数据库好像没发生变化一样,这个步骤叫回滚
。
为了记录修改前的记录
,需要将其写入到日志文件中,这个保存原来记录的日志,即undo log
。
undo log除了支持回滚数据
外,在MySQL事务详解(二):隔离级别的实现MVCC中提到过的版本链
也是通过undo log构成
所以undo log也是mvcc
中不可或缺的一部分。
undo的存储结构
undo log 通过回滚段(rollback segment)
进行管理的。每个回滚段由1024个undo slot
组成,这些undo slot里面存放的是undo链表
的第一个节点。如图:

如果在MySQL初始化时配置了undo表空间,那么回滚段就被分配到undo表空间
,否则分配到系统表空间
。
undo的类型
在MySQL的InnoDB引擎中,将undo log分为了两种类型:
• insert undo log : 对应于
insert操作
或者更新主键
产生的undo log。• update undo log : 对应
delete和update操作
产生的undo log。
将undo 分为两种类型的原因
在于:对于insert操作的记录,只对于本事务可见,事务提交后可以直接删除insert undo log
。
对于update undo log,因为mvcc机制的需要,在事务提交后还需要保持一段时间,只能等待purge线程去删除
。
所以如果一个事务同时包含着insert、delete、update操作,那么会产生不同类型的undo log。
从而会在表空间的两个slot
中生产两条不同的undo链表
。如图

undo的写入过程

1. 事务对记录做更改之前,首先去表空间(系统表空间或者undo表空间)
分配一个回滚段
(轮询算法分配),一经分配该事务就不会再分配回滚段。2. 分配到回滚段后,查询对应的
缓存链表(insert/update)
是否缓存了undo slot。如果有缓存则将缓存的undo slot 分配给该事务。3. 如果没有缓存,则在回滚段中查找可用的
undo slot
分配给该事务。如果slot都不可用则直接报错
。4. 分配到undo slot后,如果是从缓存链表中复用的,则可以直接使用。否则需要重新
分配undo log segment
,并从中申请undo页
,写入到slot中
。5. 分配完undo页后,事务
将undo log 写入到对应的页面
即可。
undo相关配置
mysql> show global variables like "%undo%";
+--------------------------+------------+
| Variable_name | Value |
+--------------------------+------------+
| innodb_max_undo_log_size | 1073741824 |
| innodb_undo_directory | ./ |
| innodb_undo_log_truncate | OFF |
| innodb_undo_logs | 128 |
| innodb_undo_tablespaces | 0 |
+--------------------------+------------+
innodb_max_undo_log_size
: 表空间的大小,默认1G。innodb_undo_directory
: undo表空间的存储路径。如果没有指定,则在MySQL的数据目录创建。innodb_undo_log_truncate
: 启用后,当表空间大小超过innodb_max_undo_log_size
,将会被截断。注意:启用时,innodb_undo_tablespaces必须大于等于2,innodb-rollback-segments必须大于等于35.innodb_undo_logs
: 回滚段数量(5.7已弃用)。与 innodb_rollback_segments同意,默认128(也是最大值)。innodb_undo_tablespaces
: 表空间大小。默认0(表示不开启undo 表空间),最大限制95。只可以初始化MySQL时指定。innodb_purge_rseg_truncate_frequency
: 系统释放回滚段的频率,以调用清除的次数为单位。默认128。undo 表空间在回滚段被释放前不能被截断。
既然已经看到这里,请随手点个赞和“在看”吧。
欢迎关注我的公众号“IT的世界”,原创技术文章第一时间推送。





