MySQL(Undo日志)

后面也会持续更新,学到新东西会在其中补充。
建议按顺序食用,欢迎批评或者交流!
缺什么东西欢迎评论!我都会及时修改的!
大部分截图和文章采用该书,谢谢这位大佬的文章,在这里真的很感谢让迷茫的我找到了很好的学习文章。我只是加上了自己的拙见我只是记录学习没有任何抄袭意思
MySQL 是怎样运行的:从根儿上理解 MySQL - 小孩子4919 - 掘金小册

先啰嗦一下之前说的表空间

前言

通用链表结构
在写入undo日志的过程中会使用到多个链表,很多链表都有同样的节点结构
在这里插入图片描述
想定位表空间内的某一个位置的话,只需指定页号以及该位置在指定页号中的页内偏移量即可。

  • Pre Node Page NumberPre Node Offset的组合就是指向前一个XDES Entry的指针
  • Next Node Page NumberNext Node Offset的组合就是指向后一个XDES Entry的指针。

整个List Node占用12个字节的存储空间。
链表的基节点。这个结构中包含了链表的头节点尾节点指针以及这个链表中包含了多少节点的信息。
在这里插入图片描述

  • List Length表明该链表一共有多少节点
  • First Node Page NumberFirst Node Offset表明该链表的头节点表空间中的位置。
  • Last Node Page NumberLast Node Offset表明该链表的尾节点表空间中的位置。

整个List Base Node占用16个字节的存储空间。
在这里插入图片描述

FIL_PAGE_UNDO_LOG页面

表空间其实是由许许多多的页面构成的,页面默认大小为16KB
这些页面有不同的类型
比如:
类型为FIL_PAGE_INDEX页面用于存储聚簇索引以及二级索引
类型为FIL_PAGE_TYPE_FSP_HDR页面用于存储表空间头部信息
类型为FIL_PAGE_UNDO_LOG页面是专门用来存储undo日志
在这里插入图片描述
FIL_PAGE_UNDO_LOG简称为Undo页面File HeaderFile Trailer是各种页面都有的通用结构
在这里插入图片描述
先就此打住!让我介绍一下其他东西加以理解!

事务回滚的需求

事务需要保证原子性,也就是事务中的操作要么全部完成,要么什么也不做。
但是也有意外出现

  • 情况一:事务执行过程中可能遇到各种错误,比如服务器本身的错误,操作系统错误,甚至是突然断电导致的错误。
  • 情况二:程序员可以在事务执行过程中手动输入ROLLBACK语句结束当前的事务的执行

这两种情况都会导致事务执行到一半就结束,但是事务执行过程中可能已经修改了很多东西,为了保证事务的原子性,需要把东西改回原先的样子,这个过程就称之为回滚(英文名:rollback)
每当我们要对一条记录做改动时(这里的改动可以指INSERTDELETEUPDATE),都需要留一手 —— 把回滚时所需的东西都给记下来

  • insert语句,至少要把这条记录的主键值记下来,之后回滚的时候只需要把这个主键值对应的记录删掉就好了。
  • delete语句,至少要把这条记录中的内容都记下来,这样之后回滚时再把由这些内容组成的记录插入到表中就好了。
  • update语句,至少要把修改这条记录前的旧值都记录下来,这样之后回滚时再把这条记录更新为旧值就好了。

为了回滚而记录这种操作称之为撤销日志,英文名为undo log,也就是undo 日志
由于查询操作(SELECT并不会修改任何用户记录,所以在查询操作执行时,并不需要记录相应的undo日志

事务id

给事务分配id的时机

一个事务可以是一个只读事务,或者是一个读写事务

  • 通过START TRANSACTION READ ONLY语句开启一个只读事务。

只读事务中不可以对普通的表(其他事务也能访问到的表)进行增、删、改操作,但可以对临时表增、删、改操作。

  • START TRANSACTION READ WRITE语句开启一个读写事务,或者使用BEGIN、START TRANSACTION语句开启的事务默认也算是读写事务

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

  • 对于只读事务来说,只有在它第一次对某个用户创建的临时表执行增、删、改操作时才会为这个事务分配一个事务id,否则的话是不分配事务id的。
  • 对于读写事务来说,只有在它第一次对某个表(包括用户创建的临时表)执行增、删、改操作时才会为这个事务分配一个事务id,否则的话也是不分配事务id的。
    有的时候虽然我们开启了一个读写事务,但是在这个事务中全是查询语句,并没有执行增、删、改的语句,那也就意味着这个事务并不会被分配一个事务id

trx_id隐藏列

在这里插入图片描述
对这个聚簇索引记录做改动的语句所在的事务对应的事务id而已(此处的改动可以是INSERTDELETEUPDATE操作)。

undo日志的格式

为了实现事务的原子性InnoDB存储引擎在实际进行增、删、改一条记录时,都需要先把对应的undo日志记下来。一般每对一条记录做一次改动,就对应着一条undo日志,但在某些更新记录的操作中,也可能会对应着2条undo日志
一个事务在执行过程中可能新增、删除、更新若干条记录,也就是说需要记录很多条对应的undo日志,这些undo日志会被从0开始编号,也就是说根据生成的顺序分别被称为第0号undo日志第1号undo日志、…、第n号undo日志等,这个编号也被称之为undo no
这些undo日志是被记录到类型为FIL_PAGE_UNDO_LOG的页面中。
在这里插入图片描述

这些页面可以从系统表空间中分配,也可以从一种专门存放undo日志表空间,也就是所谓的undo tablespace中分配。

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;

id列主键,我们为key1列建立了一个二级索引col列是一个普通的列
InnoDB的数据字典,每个表都会被分配一个唯一的table id

information_schema.innodb_sys_tables在mysql5.7中有但在mysql9.0没有

mysql> SELECT * FROM information_schema.innodb_sys_tables WHERE name = 'test/undo_demo';
+----------+----------------+------+--------+-------+-------------+------------+---------------+------------+
| TABLE_ID | NAME           | FLAG | N_COLS | SPACE | FILE_FORMAT | ROW_FORMAT | ZIP_PAGE_SIZE | SPACE_TYPE |
+----------+----------------+------+--------+-------+-------------+------------+---------------+------------+
|      233 | test/undo_demo |   33 |      6 |   253 | Barracuda   | Dynamic    |             0 | Single     |
+----------+----------------+------+--------+-------+-------------+------------+---------------+------------+
1 row in set (0.00 sec)

undo_demo表对应的table id233

INSERT操作对应的undo日志

当我们向表中插入一条记录时会有乐观插入悲观插入的区分,但是不管怎么插入,最终导致的结果就是这条记录被放到了一个数据页中。
如果希望回滚这个插入操作,那么把这条记录删除就好了,也就是说在写对应的undo日志时,主要是把这条记录的主键信息记上。
类型为TRX_UNDO_INSERT_RECundo日志,它的完整结构如下图所示:
在这里插入图片描述

  • undo no在一个事务中是从0开始递增的,也就是说只要事务没提交,每生成一条undo日志,那么该条日志的undo no就增1
  • 如果记录中的主键只包含一个列,那么在类型为TRX_UNDO_INSERT_RECundo日志中只需要把该列占用的存储空间大小真实值记录下来,如果记录中的主键包含多个列,那么每个列占用的存储空间大小和对应的真实值都需要记录下来(图中的len就代表列占用的存储空间大小value就代表列的真实值)。

向某个表中插入一条记录时,实际上需要向聚簇索引和所有的二级索引都插入一条记录。只需要考虑向聚簇索引插入记录时的情况就好了,因为其实聚簇索引记录二级索引记录是一一对应的,在回滚插入操作时,只需要知道这条记录的主键信息,然后根据主键信息做对应的删除操作,做删除操作时就会顺带着把所有二级索引中相应的记录也删除掉。
DELETE操作和UPDATE操作对应的undo日志也都是针对聚簇索引记录而言的

BEGIN;  # 显式开启一个事务,假设该事务的id为100

INSERT INTO undo_demo(id, key1, col) 
    VALUES (1, 'AWM', '狙击枪'), (2, 'M416', '步枪');

因为记录的主键只包含一个id列,所以在对应的undo

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值