前往小程序,Get更优阅读体验!
立即前往
发布
社区首页 >专栏 >MySQL 核心模块揭秘 | 53 期 | DELETE 删除的记录,ROLLBACK 怎么回滚?

MySQL 核心模块揭秘 | 53 期 | DELETE 删除的记录,ROLLBACK 怎么回滚?

作者头像
爱可生开源社区
发布2025-02-19 23:37:32
发布2025-02-19 23:37:32
6600
代码可运行
举报
运行总次数:0
代码可运行

作者:操盛春,爱可生技术专家,公众号『一树一溪』作者,专注于研究 MySQL 和 OceanBase 源码。

爱可生开源社区出品,原创内容未经授权不得随意使用,转载请联系小编并注明来源。


本文基于 MySQL 8.0.32 源码,存储引擎为 InnoDB。

正文

1. 准备工作

创建测试表:

代码语言:javascript
代码运行次数:0
复制
CREATE TABLE `t1` (
  `id` int unsigned NOT NULL AUTO_INCREMENT,
  `i1` int DEFAULT '0',
  PRIMARY KEY (`id`) USING BTREE,
  KEY `idx_i1` (`i1`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3;

插入测试数据:

代码语言:javascript
代码运行次数:0
复制
INSERT INTO `t1` (`id`, `i1`) VALUES 
(10, 101), (20, 201), (30, 301), (40, 401);

删除 <id = 40> 的记录:

代码语言:javascript
代码运行次数:0
复制
DELETE FROM t1 WHERE id = 40;

回滚:

代码语言:javascript
代码运行次数:0
复制
ROLLBACK;

2. 读取 Undo 日志

回滚 Delete 操作过程中读取 Undo 日志,和回滚 Insert 操作过程中读取 Undo 日志的流程一样,这里不再赘述。

3. 解析 Undo 日志

准备工作中,Delete 语句删除 <id = 40> 的记录产生的 Undo 日志如下:

3.1 解析参数

删除记录产生的 Undo 日志的格式,除了没有更新字段区域,剩余的其它部分和更新记录产生的 Undo 日志的格式相同。删除记录产生的 Undo 日志的参数区域,和插入记录产生的 Undo 日志的参数区域的不同之处,可以参考前面关于回滚更新记录的内容。

删除记录产生的 Undo 日志的参数区域,对应图中 offset [339, 344)

  • type_flag,值为 78,由 14 | 64 得到。 14 在代码里定义为 TRX_UNDO_DEL_MARK_REC,表示这条 Undo 日志由删除记录产生,参数区域之后的其它属性按照 TRX_UNDO_DEL_MARK_REC 类型的 Undo 日志格式解析。 64 在代码里定义为 TRX_UNDO_MODIFY_BLOB,有这个标志就意味着 Undo 日志的参数区域包含 lob_flag 属性。
  • lob_flag,因为 type_flag 中设置了 TRX_UNDO_MODIFY_BLOB 标志,所以 Undo 日志中写入了 lob_flag 属性。这个属性值硬编码为 0x00,实际上没有使用。
  • undo_no,值为 0。说明这是 Update Undo 段中第一条 Undo 日志。Delete 操作产生的 Undo 日志,也会写入到 Update Undo 段管理的 Undo 页中。
  • table_id,值为 1067。这是 <id = 40> 的记录所属表的 ID。InnoDB 会用这个 ID 打开表,用于回滚过程中的后续操作。

3.2 解析头信息和隐藏字段

头信息和隐藏字段区域,对应图中 offset [344, 358),包含 3 个属性:

  • info_bits,值为 0。这是 <id = 40> 的记录的头信息中第 1 字节第 5 ~ 8 位的值。
  • DB_TRX_ID,值为 2846。这是 <id = 40> 的记录被当前回滚事务删除之前的 DB_TRX_ID 字段值。
  • DB_ROLL_PTR,值为 36310272004456759。这是 <id = 40> 的记录被当前回滚事务删除之前的 DB_ROLL_PTR 字段值。

解析出来之后,这 3 个属性的值会保存到回滚操作内存对象(undo_node)的 update 属性中。

回滚时,这 3 个属性的值分别被拷贝到 <id = 40> 的记录的头信息、DB_TRX_ID 和 DB_ROLL_PTR 字段中。

3.3 解析主键字段

主键字段区域,对应图中 offset [358, 363),包含 2 个属性:

  • primary_field_len,值为 4。表示 t1 表的主键字段值(id = 40)在 Undo 日志中占用 4 字节。
  • primary_field_value,值为 40。这是 <id = 40> 的记录的主键字段(id)值。

解析出来之后,主键字段值保存到回滚操作内存对象(undo_node)的 ref 属性中。

3.4 二级索引字段

二级索引字段区域,对应图中 offset [363, 377),存放的是 <id = 40> 的记录对应的所有二级索引记录的字段值。

因为每个二级索引记录的末尾都包含主键字段,所以,Undo 日志的这个区域中记录了 id 字段的信息。每组 <index_field_pos, index_field_len, index_field_value> 对应一个字段的信息。

这个区域存放的二级索引字段信息,回滚时不需要解析,因为用不到。purge 线程清理标记删除的二级索引记录时才会用到。

4. 查找主键索引记录

前面从 Undo 日志中解析主键字段值(id)得到 40,保存到了回滚操作内存对象(undo_node)的 ref 属性中。现在需要根据主键字段值去主键索引的 B+ 树中查找 <id = 40> 的记录。

找到记录之后,读取记录中所有字段值,保存到回滚操作内存对象(undo_node)的 row 属性中。另外,还会保存指向主键索引 B+ 树中 <id = 40> 的记录的指针,后面回滚这条主键索引记录时会用到。

undo_node 对象的 row 属性中,既包含我们创建表时指定的字段,也包含 InnoDB 自己加上的隐藏字段 DB_TRX_IDDB_ROLL_PTR。因为我们创建表时指定了主键,记录中不会包含隐藏字段 DB_ROW_ID。row 属性中保存的各字段值如下:

  • id = 40
  • i1 = 401
  • DB_TRX_ID = 2848
  • DB_ROLL_PTR = 281474985427281

以上这些是 t1 表中 <id = 40> 的记录被当前回滚事务标记删除之后的各字段值。其中 DB_TRX_ID 是当前回滚事务的 ID,DB_ROLL_PTR 是当前 Undo 日志的地址。

另外,<id = 40> 的记录的头信息中第 1 字节第 5 ~ 8 位也发生了变化,因为这条记录已经被当前回滚事务标记删除,标记删除对应的标志位会被设置为 1。

5. 回滚二级索引记录

Delete 操作删除 t1 表中 <id = 40> 的记录,会先删除主键索引记录,然后遍历所有二级索引,每一轮遍历删除一个二级索引中的对应主键索引中 <id = 40> 的二级索引记录。回滚时,则会按照相反的顺序来,先逐个回滚二级索引记录,最后才回滚主键索引记录。

t1 表中只有一个二级索引 idx_i1,回滚流程如下:

  • 根据回滚操作内存对象(undo_node)的 row 属性中保存的 i1 和 id 字段值,构造二级索引记录 <i1 = 401, id = 40>。
  • 找到 idx_i1 中 <i1 = 401, id = 40> 的记录。
  • 取消该记录的头信息中的删除标志。这条二级索引记录就恢复为正常记录了。

6. 回滚主键索引记录

前面构造主键索引记录时,已经找到了主键索引中 <id = 40> 的记录,也保存了指向主键索引 B+ 叶子结点中 <id = 40> 的记录的指针。回滚主键索引记录时,可以直接使用这个指针操作 <id = 40> 的记录。

用回滚操作内存对象(undo_node)的 update 属性中保存的 <id = 40> 的记录的信息,回滚主键索引记录的流程如下:

  • 用 update 属性中保存的 DB_TRX_IDDB_ROLL_PTR 两个字段的值,把 <id = 40> 的记录恢复到被当前回滚事务标记删除之前的状态。
  • 用 update 属性中保存的头信息,更新 <id = 40> 的记录的头信息中第 1 字节第 5 ~ 8 位,把记录的头信息恢复到被当前回滚事务标记删除之前的状态。这个操作,就是把 <id = 40> 的记录从标记删除记录恢复为正常记录。

7. 总结

回滚 Delete 操作产生的一条 Undo 日志的主要流程如下:

  • 读取一条 Undo 日志。
  • 解析 Undo 日志。
  • 查找主键索引记录。
  • 用主键索引中查询出来的各字段值,回滚二级索引记录。
  • 用头信息和隐藏字段区域解析出来的头信息和隐藏段的值,回滚主键索引记录。
本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2025-02-18,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 爱可生开源社区 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1. 准备工作
  • 2. 读取 Undo 日志
  • 3. 解析 Undo 日志
    • 3.1 解析参数
    • 3.2 解析头信息和隐藏字段
    • 3.3 解析主键字段
    • 3.4 二级索引字段
  • 4. 查找主键索引记录
  • 5. 回滚二级索引记录
  • 6. 回滚主键索引记录
  • 7. 总结
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档