您的位置:首页 > 科技 > IT业 > 软件工程项目管理_永久免费wifi_枸橼酸西地那非片功效效及作用_鞍山网络推广

软件工程项目管理_永久免费wifi_枸橼酸西地那非片功效效及作用_鞍山网络推广

2024/12/25 0:10:18 来源:https://blog.csdn.net/weixin_45740473/article/details/142654797  浏览:    关键词:软件工程项目管理_永久免费wifi_枸橼酸西地那非片功效效及作用_鞍山网络推广
软件工程项目管理_永久免费wifi_枸橼酸西地那非片功效效及作用_鞍山网络推广

20.1 事务回滚的需求

在事务执行的过程中,可能会修改很多东西,为了能够把它们还原到原先的样子(这个过程就是回滚),就需要把所做的修改记录下来,也即 undo log。到回滚时,根据 undo log 记录进行相反的修改,就把数据库还原了,符合原子性的要求。

20.2 事务id

20.2.1 给事务分配id的时机

如果某个事务执行过程中对某个表执行了增、删、改操作,那么 InnoDB 存储引擎就会给它分配一个独一无二的事务id,分配方式如下:

  1. 对于只读事务来说,只有在它第一次对某个用户创建的临时表执行增、删、改操作时才会为这个事务分配一个事务id,否则不分配。
  2. 对于读写事务来说,只有在它第一次对某个表(包括临时表)执行增、删、改操作时才会为这个事务分配一个事务id,否则不分配。
20.2.2 事务id是怎么生成的
  • 服务器维护了一个全局变量,当要分配事务id时,把该变量的值当作事务id分配给该事务,并将该变量自增1
  • 每当这个变量的值为256的倍数时,就会将该变量的值刷新到系统表空间的页号为5的页面中一个称为 Max Trx ID 的属性处,这个属性占用8个字节的存储空间
  • 当系统下一次重启时,会将 Max Trx ID 加载到内存中,将该值加上256后赋值给那个全局变量,这样就可以保证整个系统中分配的事务id是递增的。
20.2.3 trx_id隐藏列

聚簇索引的记录除了会保存完整的用户数据以外,会自动添加名为 trx_id、roll_pointer 的隐藏列。如果用户没有在表中定义主键以及 UNIQUE 键,还会自动添加一个名为 row_id 的隐藏列。

在这里插入图片描述

22.3 undo log 的格式

为了实现事务的原子性,InnoDB 在实际进行增、删、改操作时,都需要先把对应的 undo log 记录下来。

这些 undo log 是被记录到类型为 FIL_PAGE_UNDO_LOG 的页面中的。

CREATE TABLE undo_demo (id INT NOT NULL,key1 VARCHAR(100),col VARCHAR(100),PRIMARY KEY (id),KEY idx_key1 (key1)
)Engine=InnoDB CHARSET=utf8;
SELECT * FROM information_schema.INNODB_TABLES WHERE name = 'learning/undo_demo';

在这里插入图片描述

PS:在 MySQL 8.0.3 及更高版本中,一些过时的的 InnoDB 系统表相关的代码被移除,所以某些旧版本的系统表不再是一个有效的 INFORMATION_SCHEMA 表。
基于 InnoDB 系统表的 INFORMATION_SCHEMA 视图被内部数据字典表上的系统视图所取代,受影响的 INFORMATION_SCHEMA 视图也被重命名。

以下是 InnoDB INFORMATION_SCHEMA 视图的旧名称和新名称的对应关系:

旧名称新名称
INNODB_SYS_COLUMNSINNODB_COLUMNS
INNODB_SYS_DATAFILESINNODB_DATAFILES
INNODB_SYS_FIELDSINNODB_FIELDS
INNODB_SYS_FOREIGNINNODB_FOREIGN
INNODB_SYS_FOREIGN_COLSINNODB_FOREIGN_COLS
INNODB_SYS_INDEXESINNODB_INDEXES
INNODB_SYS_TABLESINNODB_TABLES
INNODB_SYS_TABLESPACESINNODB_TABLESPACES
INNODB_SYS_TABLESTATSINNODB_TABLESTATS
INNODB_SYS_VIRTUALINNODB_VIRTUAL
20.3.1 INSERT操作对应的undo log

日志类型: TRX_UNDO_INSERT_REC

在这里插入图片描述

  1. undo no 在一个事务中是从0开始递增的。
  2. len = 列占用的存储空间;value = 列的真实值。

插入两条记录:

BEGIN; # 显式开启一个事务,假设该事务的id为100# 插入两条记录
INSERT INTO undo_demo(id, key1, col)
VALUES (1, 'AWM', '狙击枪'), (2, 'M416', '步枪');

产生的两条 undo log 如下:

在这里插入图片描述

20.3.1.1 roll pointer隐藏列的含义

roll pointer 本质上就是一个指向对应 undo log 的指针。

在这里插入图片描述

20.3.2 DELETE操作对应的undo log
  • 正常记录链表:页面中正常的记录使用记录头信息中的 next_record 属性组成的单向链表
  • 垃圾链表:被删除的记录使用记录头信息中的 next_record 属性组成的单向链表

在这里插入图片描述

使用 DELETE 语句删除数据时,分为两个阶段:

  1. 将记录的 delete_mask 标识设为1,其他不做修改。此阶段称为 delete mark。
  2. 事务提前之后,会有专门的线程把记录从正常记录链表移动到垃圾链表,并调整页面其他信息,如 PAGE_N_RECS、PAGE_LAST_INSERT、PAGE_FREE、PAGE_GARBAGE 等。此阶段称为 purge。

也就是说,回滚时,只需要考虑对 delete mark 阶段进行即可。

日志类型:TRX_UNDO_DEL_MARK_REC

在这里插入图片描述

  1. 在对一条记录进行 delete mark 操作前,需要把该记录的旧的 trx_id 和 roll_pointer 隐藏列的值都记到对应的 undo log 中来。这样就可以通过 undo log 中的 old roll_pointer 找到记录在修改之前对应的 undo log。比如在一个事务中,先插入一条数据,再将它删除:

    在这里插入图片描述

  2. 索引列各列信息:如果某个列被包含在某个索引中,那么它的相关信息就应该会被记录。pos = 该列在记录中的位置;len=该列占用的存储空间;value=该列实际值。

删除 id=1 的数据:

BEGIN; # 显式开启一个事务,假设该事务的id为100# 插入两条记录
INSERT INTO undo_demo(id, key1, col)
VALUES (1, 'AWM', '狙击枪'), (2, 'M416', '步枪');# 删除一条记录
DELETE FROM undo_demo WHERE id = 1;

在这里插入图片描述

PS:关于上述各个属性,详见[5.5 Page Header(页面头部)](###5.5 Page Header(页面头部))

20.3.3 UPDATE操作对应的undo log
20.3.3.1 不更新主键的情况
  1. 就地更新(in-place-update)

    直接在原记录的基础上修改对应列的值,每个列在更新前后占用的存储空间一样大,有任何一个列更新前后占用空间发生变化都不能进行就地更新。

  2. 先删除旧记录,再插入新记录

    当被更新列中有更新前后占用空间发生变化时,那么就需要先把这条旧的记录从聚簇索引中删掉,再插入一条新的记录。注意这里的删除是真实删除,也就是把要删除的记录从正常记录链表移动垃圾链表,并且修改页面中相应的统计信息。并且是由用户线程同步执行的。

日志类型:TRX_UNDO_UPD_EXIST_REC

在这里插入图片描述

BEGIN; # 显式开启一个事务,假设该事务的id为100# 插入两条记录
INSERT INTO undo_demo(id, key1, col) 
VALUES (1, 'AWM', '狙击枪'), (2, 'M416', '步枪');# 删除一条记录
DELETE FROM undo_demo WHERE id = 1;# 更新一条记录
UPDATE undo_demo 
SET key1 = 'M249', col = '机枪' 
WHERE id = 2;

此时采用的是就地更新的方式执行,真正发动页面记录前,会记录一条类型为TRX_UNDO_UPD_EXIST_REC的 undo log。

在这里插入图片描述

20.3.3.2 更新主键的情况

分为两步处理:

  1. 对旧记录进行 delete mark 操作,并记录一条 TRX_UNDO_DEL_MARK_REC 的 undo log。
  2. 根据更新后各列的值创建一条新记录,并将其插入到聚簇索引中(需要重新定位插入的位置),记录一条 TRX_UNDO_INSERT_REC 的 undo log。
20.3.4 增删改操作对二级索引的影响
UPDATE undo_demo
SETkey1 = 'P92',col = '手枪'
WHEREid = 2;

由于更新了二级索引的键值,所以要进行以下两个操作:

  1. 对旧的二级索引记录执行 delete mark 操作
  2. 根据更新后的值创建一条新的二级索引记录,并在 B+ 树中重新定位插入

此操作会修改当前页的最大事务id PAGE_MAX_TRX_ID 属性。

20.3.5 小结
开始
结束
操作类型
INSERT
DELETE
UPDATE
TRX_UNDO_INSERT_REC
TRX_UNDO_DEL_MARK_REC
TRX_UNDO_UPD_EXIST_REC
TRX_UNDO_INSERT_REC + TRX_UNDO_DEL_MARK_REC
是否更新主键

20.4 通用链表结构

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

20.5 FIL_PAGE_UNDO_LOG页面

FIL_PAGE_UNDO_LOG 类型页面是专门用来存储 undo log 的页面类型。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

在这里插入图片描述

属性占用空间(byte)含义
TRX_UNDO_PAGE_TYPE2存储什么种类的 undo log。TRX_UNDO_INSERT(十进制表示为1)对应 TRX_UNDO_INSERT_REC 类型的 undo log;TRX_UNDO_UPDATE(十进制表示为2)对应除TRX_UNDO_INSERT_REC 类型的 undo log。不同类型的 undo log 不能混着存储。
TRX_UNDO_PAGE_START2表示在当前页面中是什么位置开始存储 undo log 的,也即第一条 undo log 在本页面中的起始偏移量。
TRX_UNDO_PAGE_FREE2表示当前页面最后一条 undo log 在本页面中的起始偏移量,也即从这个位置开始可以继续写入新的 undo log。
TRX_UNDO_PAGE_NODE12代表一个 List Node 结构。

20.6 Undo页面链表

20.6.1 单个事务中的Undo页面链表

一个事务可能包含多个语句,更新多条记录,产生多条 undo log,一个页面放不下时需要放到多个页面中,这些页面就通过上述的 TRX_UNDO_PAGE_NODE 属性形成一个链表:

在这里插入图片描述

第一个链表节点称为 first undo page;其余的则称为 narmal undo page。

因为 TRX_UNDO_INSERTTRX_UNDO_UPDATE 不能存在同一个页面,所以这样的链表其实有两条:

在这里插入图片描述

又因为 InnoDB 规定对普通表的临时表的记录发动时产生的 undo log 要分别记录,所以一个事务中最多有4个由 Undo 页面组成的链表:

在这里插入图片描述

这些链表并不是事务一开始就存在的,而是按需分配,啥时候需要再分配,不需要就不分配。

20.6.2 多个事务中的Undo页面链表

为了提高 undo log 的写入效率,不同事务执行过程中产生的 undo log 需要被写入到不同的 Undo Page 链表中。

20.7 undo日志具体写入过程

20.7.1 段(Segemnt)的概念

是一个逻辑上的概念,本质上是由若干个零散页面和若干个完整的区组成。每个段对应一个 INODE Entry 结构,描述这个段的各种信息,如段的 ID,段内各种链表基节点,零散页面的页号等。为了定位一个 INODE Entry,InnoDB 提供了 Segemnt Header 结构:

在这里插入图片描述

  1. Space ID of the INODE Entry:INODE Entry 结构所在的表空间 ID
  2. Page Number of the INODE Entry:INODE Entry 结构所在的页面页号
  3. Byte Offset of the INODE Entry:结构在该页面中的偏移量
20.7.2 Undo Log Segemnt Header

InnoDB 规定每个 Undo 页面链表都对应着一个段,称为 Undo Log Segemnt。其中 first undo page 中设计了一个称为 Undo Log Segemnt Header 的部分:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

在这里插入图片描述
在这里插入图片描述

  1. TRX_UNDO_STATE :本 Undo Page 链表处在什么状态。

    一个 Undo Log Segment 可能处在的状态包括:

    • TRX_UNDO_ACTIVE :活跃状态,也就是一个活跃的事务正在往这个段里边写入 undo日志

    • TRX_UNDO_CACHED :被缓存的状态。处在该状态的 Undo页面 链表等待着之后被其他事务重用。

    • TRX_UNDO_TO_FREE :对于 insert undo 链表来说,如果在它对应的事务提交之后,该链表不能被重用,那么就会处于这种状态。

    • TRX_UNDO_TO_PURGE :对于 update undo 链表来说,如果在它对应的事务提交之后,该链表不能被重用,那么就会处于这种状态。

    • TRX_UNDO_PREPARED :包含处于 PREPARE 阶段的事务产生的 undo日志 。

  2. TRX_UNDO_LAST_LOG :本 Undo Page 链表中最后一个 Undo Log Header 的位置。

  3. TRX_UNDO_FSEG_HEADER :本 Undo Page 链表对应的段的 Segment Header 信息。

  4. TRX_UNDO_PAGE_LIST : Undo Page 链表的基节点。

20.7.3 Undo Log Header

同一个事务向一个 Undo Page 链表写入的 undo log 是一个组,不同的链表就是不同的组。

在这里插入图片描述

在这里插入图片描述

  1. TRX_UNDO_TRX_ID :生成本组 undo log 的事务 id 。
  2. TRX_UNDO_TRX_NO :事务提交后生成的一个需要序号,使用此序号来标记事务的提交顺序(先提交的此序号小,后提交的此序号大)。
  3. TRX_UNDO_DEL_MARKS :标记本组中有没有 Delete mark 操作产生的 undo log。
  4. TRX_UNDO_LOG_START :表示本组第一条日志在页面中的偏移量。
  5. TRX_UNDO_XID_EXISTS :本组是否包含XID信息。
  6. TRX_UNDO_DICT_TRANS :标记本组 undo log 是不是由 DDL 语句产生的。
  7. TRX_UNDO_TABLE_ID :如果 TRX_UNDO_DICT_TRANS 为真,那么本属性表示DDL语句操作的表的 table id 。
  8. TRX_UNDO_NEXT_LOG :下一组的 undo log 在页面中开始的偏移量。
  9. TRX_UNDO_PREV_LOG :上一组的 undo log 在页面中开始的偏移量。一般来说一个 Undo Page 链表只存储一个事务执行过程中产生的一组 undo log,但是在某些情况下,可能会在一个事务提交之后,之后开启的事务重复利用这个 Undo Page 链表,这样就会导致一个 Undo Page 中可能存放多组 undo log,TRX_UNDO_NEXT_LOG和TRX_UNDO_PREV_LOG就是用来标记下一组和上一组undo日志在页面中的偏移量的。关于什么时候重用Undo页面链表。
  10. TRX_UNDO_HISTORY_NODE :一个12字节的 List Node 结构,代表一个称之为 History 链表的节点。
20.7.4 小结
  1. 对于没有被重用的 Undo Page 链表来说,链表的 first undo page 在真正写入 undo log 前,会填充 Undo Page Header 、 Undo Log Segment Header 、 Undo Log Header 这三个部分,之后才开始正式写入 undo log 。而对于 normal undo page 只会填充 Undo Page Header 两个部分。

  2. 链表的 List Base Node 存放到 first undo page 的 Undo Log Segment Header 部分, List
    Node 信息存放到每一个 Undo页面 的 undo Page Header 部分。

在这里插入图片描述

20.8 重用Undo页面

在事务提交后,某些情况下可以重用事务的 Undo Page 链表。重用条件如下:

  1. 该链表中只包含一个 Undo Page。
  2. 该 Undo Page 已经使用的空间不足3/4

20.9 回滚段

20.9.1 回滚段的概念

一个事务在执行过程中最多可以分配4个 Undo Page 链表,使用 Rollback Segemnt Header 页面来管理这些链表。 Rollback Segemnt Header 存放了各个 Undo Page 链表的 first undo page 的页号。

在这里插入图片描述

InnoDB 规定,每个 Rollback Segemnt Header 页面对应一个段,这个段就称为 Rollback Segemnt,即回滚段

  • TRX_RSEG_MAX_SIZE :本 Rollback Segment 中管理的所有 Undo页面 链表中的 Undo页面 数量之和的最大值。换句话说,本 Rollback Segment 中所有 Undo页面 链表中的 Undo页面 数量之和不能超过TRX_RSEG_MAX_SIZE 代表的值。该属性的值默认为无限大(4字节能表示的最大数)。
  • TRX_RSEG_HISTORY_SIZE : History 链表占用的页面数量。
  • TRX_RSEG_HISTORY : History 链表的基节点。
  • TRX_RSEG_FSEG_HEADER :本 Rollback Segment 对应的10字节大小的 Segment Header 结构,通过它可以找到本段对应的 INODE Entry 。
  • TRX_RSEG_UNDO_SLOTS :各个 Undo 页面链表的 first undo page 的 页号 集合,也就是 undo slot 集合。
    一个页号占用 4 个字节,对于 16KB 大小的页面来说,这个 TRX_RSEG_UNDO_SLOTS 部分共存储了 1024 个
    undo slot ,所以共需 1024 × 4 = 4096 个字节
20.9.2 从回滚段中申请Undo Page链表
  1. 初始状态下,由于未向任何事务分配任何 Undo Page 链表,所以 Rollback Segemnt Header 的各个 undo slot 都被设置成一个特殊的值:FIL_NULL(对应的十六进制:0xFFFFFFFF)
  2. 当需要分配 Undo Page 链表时,就从第一个非 FIL_NULL 的 undo slot 开始,如果没有(最多1024个),就报错:Too many active concurrent transactions
  3. 当事务提交时,它所占用的 undo slot 有两种命运:
    • 如果符合重用条件,就被加到 insert undo cached 链表或 update undo cached 链表(根据他们原来的 Undo Page 链表的类型)
    • 如果不符合重用条件,根据 Undo Page 链表的类型不同,会被直接释放或加到 History 链表。
20.9.3 多个回滚段

一个回滚段只有 1024 个 undo slot,也就是说即使一个事务只分配1个 Undo Page 链表,那也只能运行 1024 个读写事务同时执行。

为了解决这个问题, InnoDB 定义了128个回滚段。

每个回滚段对应着一个 Rollback Segemnt Header 页面,这128个页面被存储在系统表空间的第5号页面。

在这里插入图片描述

20.9.4 回滚段的分类

两类:

  1. 第0号、第33-127号属于一类
  2. 第1~32号属于一类

针对普通表和临时表划分不同种类回滚段的原因:在修改针对普通表的回滚段中的 Undo Page 时,需要记录对应的 redo log,而修改针对临时表的回滚段中的 Undo Page 时,不需要记录对应的 redo log。

20.9.5 为事务分配Undo Page链表详细过程

如果一个事务在执行过程中即对普通表的记录做了改动,又对临时表的记录做了改动,那么需要为这个记录分配2个回滚段。并发执行的不同事务其实也可以被分配相同的回滚段,只要分配不同的 undo slot 即可。

20.10 回滚段相关配置

20.10.1 配置回滚段数量

innodb_rollback_segments:回滚段数量,默认128。

20.10.2 配置undo表空间
  1. innodb_undo_directory:指定 undo 表空间所在的目录
  2. innodb_undo_tablespaces:指定 undo 表空间的数量,默认0

20.11 undo log在崩溃恢复时的作用

  1. 服务器崩溃恢复时,首先按照 redo log 将各个页面的数据恢复到崩溃之前的状态,这样就保证了已经提交的事务的持久性
  2. 但是因为有些没有提交的事务写的 redo log 可能已经刷盘了,所以会把它们也恢复,为了保证事务的原子性,需要把这些操作回滚
  3. 通过表空间的第5个页面定位到128个回滚段的位置
  4. 找到每个段中不为 FIL_NULL 的 undo slot 对应的 Undo Page 链表
  5. 从 Undo Page 链表第一个页面的 Undo Segemnt Header 中找到 TRX_UNDO_STATE 属性,如果该属性为 TRX_UNDO_ACTIVE,意味着有一个活跃的事务正在向这个链表写入 undo log。
  6. 再在 Undo Segemnt Header 中找到 TRX_UNDO_LAST_LOG 属性,该属性指向的事务id就是未提交的事务,把这个事务所有操作回滚,就保证了事务的原子性

20.12 总结

  1. undo log 记录了回滚一个操作所有的必要内容,保证了事务的原子性
  2. 不同的场景有不同的 undo log 类型
  3. 类型为 FIL_PAGE_UNDO_LOG 的页面是专门用来存储 undo log 的,称为 Undo Page。
  4. 一个事务最多分配4个链表
  5. 每个 Undo Page 链表都对应一个 Undo Log Segemnt
  6. 同一个事务向一个 Undo Page 链表中写入的 undo log 算一个组
  7. Undo Page 链表可以被重用
  8. 每一个 Rollback Segemnt Header 页面都对应一个回滚段,包含1024个 undo slot,每个 undo slot 代表一个 Undo Page 链表的第一个页面的页号

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com