⚠️接下来的几篇文章,来好好聊聊 事务和与之相关的日志类型,还有最为重要的
”MVCC
undo log 设计的目的是为了记录回滚中的信息。不同类型的操作产生的 undo log 是不同的。既然涉及到事务,就来看看 事务id 是什么东西。
事务id
事务可以是一个只读事务,也可以是一个读写事务:
只读事务不能对其他事务也能访问到的表进行
crud操作,不过可以对临时表进行操作;start transaction read only读写事务是可以表进行
crud操作;start transaction read write
如果一个事务在执行过程中进行了 crud 操作,那么 InnoDB 会给你分配一个独一无二的 事务id;
事务id 的生成:server 会在内存中维护一个全局变量,需要一个分配一个,然后 ++。id 达到 256 倍数时,会持久化到系统表空间的 Max Trx ID 中;当系统重启时,会把 Max Trx ID 刷新到内存中,将该值 +256 作为全局变量。从而保证了 事务id 的递增。
undo log 的格式
为了实现事务的原子性,InnoDB 在每一个 insert,delete,update 的操作,都会把对应的 undo log 记录下来。所以与之对应的每一条 undo log 都会对应一个 undo no。
insert
插入一些测试数据,然后来看看在 page 里面发生了什么:
insert into trace(key, typeof) values
("20041", "key"), ("20041.14", "buttonkey")
在一次批量插入语句中,事务是一起进行的,所以紫色块中显示的 事务id 是一样的,但是每条对应的 undo log 的 undo no 是不一样的,因为这需要对应;
而里面的 pointer 就是 roll_pointer,指向的是对应 undo log 的开头地址。
delete
现在开始删除数据:
- 删除的时候仅仅把
delete_mask标志位置位为1,同时也会修改trx_id, roll_pointer这些隐藏列的值。但是记录还是存在正常记录链表中,也就是一个中间状态 ==>mark deleted(用了一下kafka的删除状态标志)。
⚠️至于为什么没有立即马上直接改变链表结构,这个就和
”MVCC有关了,后面会介绍。
置位之后,紧接着就会有专门的线程开始操作:
- 该记录会从
正常记录链表中删除; - 加入
垃圾链表,头插法; - 调整page的参数,比如
垃圾链表头的指针,页面可重用字节数。。。
以上被称为
purge阶段。- 该记录会从
举个实际例子来说明一下:
-- 显式开启一个事务,假设该事务的id为100
BEGIN;
-- 插入两条记录
INSERT INTO undo_demo(key, type)
VALUES ('20041', 'AMM'), ('20041.14', 'KMQ');
-- 删除一条记录
DELETE FROM undo_demo WHERE id = 1;
来看看中间状态对应的 undo log 结构:
从结构上我们看到 mark deleted 之后对于的 undo log 和之前的 insert 串成一个链表。而这个链表就称为 版本链。【后面讲到的 MVCC 就有这种 版本链】
和 insert 不一样的地方的,有一个 索引列各列信息 。记录的是索引包含的列信息,格式为 <pos,len,value>,【该列在记录的位置,占有的空间大小,实际数据值】。这个部分的信息主要是用在事务提交之后,对 mark deleted 做真正删除的第二步,也就是 purge 阶段。具体如何使用之后可以看到~~~
以上的阶段我们从宏观上观察如下:
update
⚠️带更新,带制作
”
本文使用 mdnice 排版