悔棋.
undo 日志记录了一些进行 undo 操作的元数据.
事务id
给事务分配id的时机
在只读事务中不可以对普通的表(其他事务也能访问到的表)进行增、删、改操作,但可以对临时表做增、删、改操作。
如果某个事务执行过程中对某个表执行了增、删、改操作,那么InnoDB存储引擎就会给它分配一个独一无二的事务id,分配方式如下:
- 对于只读事务来说,只有在它第一次对某个用户创建的临时表执行增、删、改操作时才会为这个事务分配一个事务id,否则的话是不分配事务id
- 对于读写事务来说,只有在它第一次对某个表(包括用户创建的临时表)执行增、删、改操作时才会为这个事务分配一个事务id,否则的话也是不分配事务id
有的时候虽然我们开启了一个读写事务,但是在这个事务中全是查询语句,并没有执行增、删、改的语句,那也就意味着这个事务并不会被分配一个事务id。
事务id是怎么生成的
- 服务器会在内存中维护一个全局变量,每当需要为某个事务分配一个事务id时,就会把该变量的值当作事务id分配给该事务,并且把该变量自增1。
- 每当这个变量的值为256的倍数时,就会将该变量的值刷新到系统表空间的页号为5的页面中一个称之为Max Trx ID的属性处,这个属性占用8个字节的存储空间。
- 当系统下一次重新启动时,会将上边提到的Max Trx ID属性加载到内存中,将该值加上256之后赋值给我们前边提到的全局变量
trx_id隐藏列
一条记录在页面中的真实结构看起来就是这样的:

undo日志的格式
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;
可以通过系统数据库information_schema中的innodb_sys_tables表来查看某个表对应的table id是什么:
mysql> SELECT * FROM information_schema.innodb_sys_tables WHERE name = 'xiaohaizi/undo_demo';
+----------+---------------------+------+--------+-------+-------------+------------+---------------+------------+
| TABLE_ID | NAME | FLAG | N_COLS | SPACE | FILE_FORMAT | ROW_FORMAT | ZIP_PAGE_SIZE | SPACE_TYPE |
+----------+---------------------+------+--------+-------+-------------+------------+---------------+------------+
| 138 | xiaohaizi/undo_demo | 33 | 6 | 482 | Barracuda | Dynamic | 0 | Single |
+----------+---------------------+------+--------+-------+-------------+------------+---------------+------------+
1 row in set (0.01 sec)
INSERT操作对应的undo日志
undo insert 操作其实就是删除那条记录, 在写对应的undo日志时,主要是把这条记录的主键信息记上

- undo no在一个事务中是从0开始递增的,也就是说只要事务没提交,每生成一条undo日志,那么该条日志的undo no就增1。
- 如果记录中的主键只包含一个列,那么在类型为TRX_UNDO_INSERT_REC的undo日志中只需要把该列占用的存储空间大小和真实值记录下来,如果记录中的主键包含多个列,那么每个列占用的存储空间大小和对应的真实值都需要记录下来
向undo_demo中插入两条记录:
BEGIN; # 显式开启一个事务,假设该事务的id为100
# 插入两条记录
INSERT INTO undo_demo(id, key1, col)
VALUES (1, 'AWM', '狙击枪'), (2, 'M416', '步枪');
本例中插入了两条记录,所以会产生两条类型为TRX_UNDO_INSERT_REC的undo日志:
- 第一条undo日志的undo no为0,记录主键占用的存储空间长度为4,真实值为1。

- 第二条undo日志的undo no为1,记录主键占用的存储空间长度为4,真实值为2。

roll_pointer隐藏列的含义
本质上就是一个指向记录对应的undo日志的一个指针。

