undo日志的目的:事务执行到一半突然终止,已经修改的脏页如果恢复原状.与redo针对事务提交操作不同,undo日志针对事务的回滚操作.
1. undo日志的格式
为方便下面的学习,我们先建立下表
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;
查看table_id
1. 插入操作对应的undo日志
我们对表插入一条记录时,需要同时修改二级索引和聚簇索引中的记录,==但由于聚簇索引记录与二级索引记录意义对应,所以只针对聚簇索引记录缠身undo日志记录即可,当需要回滚时,根据聚簇索引中主键id回表查找到二级索引所对应的记录,执行逆操作即可.
undo日志对应的结构如下:
插入两条数据
INSERT INTO undo_demo(id,key1,col) VALUES(1,'AWM','狙击枪') ,(2,'M416','步枪');
mysql> select * from undo_demo;
+----+------+-----------+
| id | key1 | col |
+----+------+-----------+
| 1 | AWM | 狙击枪 |
| 2 | M416 | 步枪 |
+----+------+-----------+
2 rows in set (0.00 sec)
此时undo日志
undo日志存储在 undo_log 类型的页面中,其与 page_index类型页面的数据记录的关系如下
2. 删除操作对应的日志
被删除的记录会形成一个垃圾链表,记录头部的page_free 属性会指向该链表,该链表的空间可以被重复利用.
删除记录的两个阶段
- delete mark 阶段,在事务提交前,一直处于delete mark 阶段
- purge 阶段
当事务提交,将该记录加入垃圾链表头部,修改 page_free等属性(修改很多属性)的值.
删除undo日志结构
删除一条记录
mysql> delete from undo_demo where id=1;
Query OK, 1 row affected (0.01 sec)
mysql> select * from undo_demo;
+----+------+--------+
| id | key1 | col |
+----+------+--------+
| 2 | M416 | 步枪 |
+----+------+--------+
1 row in set (0.00 sec)
此时innodb内部情形如下
3. 更新操作的undo日志
不更新主键的undo日志
就地更新
更新操作是对一条记录(一行),进行操作,每行包括多列,如果更新前后,每列的所占空间的大小不变,则就地更新.
删除-更新
如果更新前后有的列的存储空间发生变化,则将该条旧记录删除(直接删除,加入垃圾链表的表头),并更新相关属性.如果新纪录的空间不超过旧记录,直接在旧记录的位置征信,否则在页面中申请一块空间.
不更新主键的日志格式
执行下面语句,此时更新一条记录,INNODB 内部情形如下
update undo_demo set key1 ='M249',col='机枪' where id=2;
mysql> select * from undo_demo;
+----+------+--------+
| id | key1 | col |
+----+------+--------+
| 2 | M249 | 机枪 |
+----+------+--------+
1 row in set (0.00 sec)
更新主键的undo日志
更新主键值的操作,首先会delete mark(?支持MVCC),然后创建一条新纪录插入到聚簇索引中,整个过程对应上面介绍的 删除undo日志个插入undo日志