5、undo log
2021-10-16 16:36:45 2 举报
Undo log是数据库系统中用于实现事务原子性和持久性的关键组件。当一个事务开始时,系统会为其创建一个undo log,用于记录该事务执行过程中产生的所有修改操作。在事务提交前,这些修改操作仅存在于内存中,并未真正写入磁盘。如果此时发生故障,系统可以通过回滚事务来撤销这些未完成的修改操作,从而保证数据的一致性和完整性。 为了实现高效的回滚操作,undo log通常采用链表或树状结构进行组织。每个修改操作都会生成一个日志条目,包含修改前后的数据值、操作类型等信息。在事务回滚时,系统会根据这些信息依次撤销修改操作,恢复数据到事务开始前的状态。
作者其他创作
大纲/内容
事务开始
数据:C
表ID
数据:NULL
每条数据都有两个隐藏字段
值B
id > 10 的数据有15条
trx_id=45
45
min_trx_id
提交事务
事务A
原始值
万一现在在buffer pool的一个缓存页里插入了一条数据了,执行了insert语句,然后写了一条上面的那种undo log,现在事务要是回滚了,直接就把这条insert语句的undo log拿出来。然后在undo log里就知道在哪个表里插入的数据,主键是什么,直接定位到那个表和主键对应的缓存页,从里面删除掉之前insert语句插入进去的数据就可以了,这样就可以实现事务回滚的效果了
4.查询数据为NULL
一行数据
事务A(id=50)
2.更新数据为B
45、59
5.查询结果为A
9.插入一条数据
最近一次更新这条数据的事务id
事务C
主键<列长度,列值>
事务A查询的数据结果比之前多
这行数据的 txr_id(78)大于 ReadView 中的 max_trx_id(60)说明这行数据是事务A开启之后,有一个事务更新了数据,所以对这行数据是不能查询的故事务A根据undo log版本链找到上一条undo log【事务A之前修改过的版本, txr_id(45)等于 ReadView 中的 creator_trx_id(45)】,此时直接读取之前自己修改的版本,查询的结果为A
多个事务串行执行的时候,每个事务修改一行数据,都会更新隐藏字段txr_id和roll_pointer同时之前多个数据快照对应的undo log,会通过roll_pinter指针串联起来,形成一个重要的版本链
id为50的事务A插入一条记录,此时这条数据的隐藏字段以及指向undo log如图所示roll_pointer指向一个空的undo log,因为之前这条数据是没有的
事务A(id=45)和事务B(id=59)和事务B并发执行事务A开启 ReadView 如下:
undo log日志类型
这行数据的 txr_id(59) 大于 ReadView 中的 min_trx_id(45),小于max_trx_id(60)并且59在m_ids(45、59)中说明修改数据的事务B是跟事务A同一时段并发执行然后提交的,所以对这行数据是不能查询的故事务A根据undo log版本链找到上一条undo log【trx_id(32)小于min_trx_id(45)】,此时查询结果就为X
9
roll_pointer
undo log日志编号
4.更新数据为C
值A
7
MySQL下一个要生成的事务id,就是最大事务id
2.修改值为B
1.查询结果为X
用undo log日志去回滚
trx_id=30
3
RR级别下,事务中的第一个SELECT请求才开始创建read view,而不是事务刚启动时就创建;RC级别下,事务中每次SELECT请求都会重新创建read view;
creator_trx_id
事务B
undo log(空的)
举例说明undo log版本链的机制
5.查询数据为C
生成ReadView
事务B(id=58)
事务A(id=45)
undo log日志结束位置
事务D(id=80)
事务C(id=78)
数据库表中的一条原始数据
数据:B
10.查询id>10的数据有1条(id=11的数据)
3.查询结果为X
这行数据的 txr_id 变为59,同时roll_pointer指向了修改之前生成的一个undo log
用数据A做业务处理
3.事务回滚
执行一个事务的时候,会生成一个ReadView
值C
undo log 记录更新之前这行数据为NULL,主键为X
undo log日志开始位置
这行数据的 txr_id(45)等于 ReadView 中的 creator_trx_id(45)说明这行数据是事务A自己修改的,自己修改的值是可以看到的
id=12
trx_id
事务B提交了数据,事务A查询重新生成 ReadView,数据库内活跃的事务只有事务A了这行数据的txr_id(59)虽然在min_trx_id和max_trx_id范围之间但是50不在m_ids(45、59)中说明事务B在生成本次ReadView之前就已经提交了,所以本次查询可以查到事务B修改的值
4.查询结果为B
trx_id=59
导致事务B修改的值没有了
undo log多版本链的作用:可以保存一个快照链条,读到之前的快照值通过这套 ReadView+undo log 日志链条的机制,就可以保证事务A不会读到并发执行的事务B更新的值,只会读到之前最早的值
此时数据未提交
trx_id=50
1
1.查询数据为A
事务A每次查询的这个数据的结果不同
事务C(id=69)
不可重复读:事务A在执行期间多次查询一条数据,每次都可以查到其他已经提交的事务修改过的值
事务B(id=59)
id=11
5
7.查询结果为A
m_ids
id为58的事务B修改这条数据,将值改为B此时更新之前会生成一个undo log记录之前的值,然后让roll_pointer指向这个实际的undo log回滚日志
undo log:提供回滚和多个行版本控制(MVCC)是InnoDB MVCC事务特性的重要组成部分当delete一条记录时,undo log中会一条对应的insert记录当update一条记录时,undo log记录一条对应相反的update记录当insert一条记录,undo log记录主键和一个对应的delete操作
4
max_trx_id
数据:A
60
3.查询数据为B
事务B再次查询发现数据为NULL
m_ids里最小的值
undo log版本链的机制
原始值(X)
左图对应步骤讲解
脏写:事务B修改了事务A修改过的值,但是此时事务A还没提交,当事务A回滚时,会将值变成事务A修改之前的值,导致事务B修改的值也没了
脏读:事务B查询了事务A修改过的数据,但是此时事务A还没提交,当事务A回滚时,导致事务B再次查询就读不到刚才事务A修改的数据了
1.更新数据为A
2.插入5条数据
新增数据的 txr_id(80)大于 ReadView 中的 max_trx_id(60)说明这行数据是事务A开启之后,有一个事务新增了数据,所以对这行数据是不能查询的因此事务A本次查询,还是只能查到原始值一条数据
当前事务的id
trx_id=58
undo log 数据格式
RC隔离级别基于ReadView机制实现原理当一个事务设置RC隔离级别的时候,是每次发起查询,都重新生成一个ReadView
不管别的事务如何修改数据,事务的ReadView始终是不变的
举例说明
4.更新值为A
存放此时有哪些事务在MySQL里执行还没提交
8.查询id>10的数据有1条(id=11的数据)
trx_id=80
2
指向更新这个事务之前生成的undo log
6.修改值为C
1.查询出10条数据
id > 10 的数据有10条
基于undo log多版本链实现的ReadView机制
RR隔离级别基于ReadView机制实现原理
id为69的事务C修改这条数据,将值改为C
这行数据的 txr_id(30) 小于 ReadView 中的 min_trx_id(45)说明事务A开启之前,修改这行数据的事务已经提交了,所以此时可以查到这行数据
幻读的处理方式
trx_id=78
3.查询出15条数据
2.查询数据为A
trx_id=69
trx_id=40
数据
幻读:查询到了之前查询没看到过的数据
此时事务B提交了数据
0 条评论
下一页