Undo Log
事务的第一个特性就是原子性,原子性就是要保证一个事务中的增删改操作要么都成功,要么都不做。这时就需要 undo log,在对数据库进行修改前,会先记录对应的 undo log,然后在事务失败或回滚的时候,就可以用这些 undo log 来将数据回滚到修改之前的样子。
下面先简单介绍下事务ID和行记录中的隐藏列,因为后面的内容都与这两个东西有关系。
事务ID
事务执行过程中在对某个表执行增、删、改操作时,InnoDB就会给这个事务分配一个唯一的事务ID。如果一个事务中没有执行增删改操作,就不会分配事务ID。
InnoDB 在内存维护了一个全局变量来表示事务ID,每当要分配一个事务ID时,就获取这个变量值,然后把这个变量自增1。每当这个变量的值为256的倍数时,就会将该变量的值刷新到系统表空间的页号为5的页面中一个称之为Max Trx ID的属性处。当系统下一次重新启动时,会将Max Trx ID属性加载到内存中,并将该值加上256之后赋值给这个全局变量(这个过程跟主键row_id的分配是类似的)。
我们可以通过
information_schema.INNODB_TRX 来查询当前系统中运行的事务信息,这张表的第一个字段trx_id就是事务ID。
mysql> SELECT trx_id,trx_state,trx_started,trx_rows_locked,trx_isolation_level,trx_is_read_only FROM information_schema.INNODB_TRX;
+-----------+-----------+---------------------+-----------------+---------------------+------------------+
| trx_id | trx_state | trx_started | trx_rows_locked | trx_isolation_level | trx_is_read_only |
+-----------+-----------+---------------------+-----------------+---------------------+------------------+
| 164531720 | RUNNING | 2021-05-14 16:38:59 | 1 | REPEATABLE READ | 0 |
+-----------+-----------+---------------------+-----------------+---------------------+------------------+
行记录隐藏列
在介绍InnoDB行记录格式这篇文章中,我们了解到行记录中会有三个隐藏列:
- DB_ROW_ID:如果没有为表显式的定义主键,并且表中也没有定义唯一索引,那么InnoDB会自动为表添加一个row_id的隐藏列作为主键。
- DB_TRX_ID:事务中对某条记录做增删改时,就会将这个事务的事务ID写入trx_id中。
- DB_ROLL_PTR:回滚指针,本质上就是指向 undo log 的指针。
Undo Log 类型
每对一条记录做一次改动,就会产生1条或者2条 undo log。一个事务中可能会有多个增删改SQL语句,一个SQL语句可能会产生多条 undo log,一个事务中的这些 undo log 会被从 0 开始递增编号,这个编号称为 undo no。
undo log 主要是记录对数据库增删改的撤销日志,下面就分别来看下增删改操作的 undo log 格式是怎样的。
还是以之前的 account 表为例来做一些演示。
CREATE TABLE `account` (
`id` bigint(11) NOT NULL AUTO_INCREMENT COMMENT '主键',
`card` varchar(60) NOT NULL COMMENT '卡号',
`balance` int(11) NOT NULL DEFAULT '0' COMMENT '余额',
PRIMARY KEY (`id`),
UNIQUE KEY `account_u1` (`card`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='账户表';
我们可以通过
information_schema.INNODB_SYS_TABLES 查询得到这张表的表空间ID为 13881。
mysql> SELECT * FROM information_schema.