Undo日志
- Undo日志保证了事务原子性
- 每次更新一条数据之前都会先写入一条undo日志
- 在运行过程中,如果数据库宕机或是事务回滚,都需要把数据恢复成原来的样子,这个由Undo日志完成
SELECT
没有修改数据记录,不会产生Undo日志- Undo日志每次记录的都是相反的操作,如果修改操作错误,可以通过执行这些相反操作把数据恢复回去。
作用
- 1.回滚数据(数据虽然回滚,但是只是逻辑上恢复了原装,物理存储上的改变无法恢复)
- 2.实现MVCC
存储结构
Undo日志的结构由回滚段和undo页组成
- Undo日志中的空间划分为一个个的段,称为回滚段(
rollback segment
),共有128个段,每个段中有1024个undo页 - undo页可以重复使用,如果当前事务写入的记录小于页空间的3/4,那其他事务可以继续写入。
回滚段与事务
- 一个事务只用一个回滚段,一个回滚段可能同时服务于多个事务
- 事务中的数据修改时,原始的数据会被复制到回滚段中
- 每次事务提交时,存储引擎会将undo日志页放入链表中,等待清除,并判断是否需要重用,如果可以重用就分配给下个事务
undo类型
- 插入页:在进行insert操作时产生的日志记录,由于insert只有事务本身可见,其他事务不可见,所以事务提交后insert日志页可以直接删除,不需要purge操作
- 更新页:在进行删除或更新时产生的日志记录。更新页需要参与多版本机制(
MVCC
),所以事务提交后一般不会删除,会放入链表,等待purge线程清除。
生命周期/运行过程
在有Buffer Pool、Redo、Undo日志的情况下,更新一次数据流程:
- 插入
比如执行操作:
begin;
insert into user(name) values("tom");
具体执行一次insert操作时,会生成一条undo日志,数据记录中的回滚指针会指向它,日志中记载了日志序号、主键的列、值等信息.
- 更新
update user set name="Sun" where id=1;
会创建一个新的日志页,将旧记录复制到新页,回滚指针指向新页,新页指向旧页.
如果更新主键,会将deletemark标识为1,然后在后面插入一个新的数据,数据也会产生新的日志页,并且日志页的序号是递增的
在进行回滚时,按序号依次向前推就可以找到原始数据.
通过3找到2,通过2找到1,将1的deletemark标识改回0.