赞
踩
原子性是事务的其中一个特性,指的是要么全部执行完,要么全都不执行,说的容易,如何保证这一特性呢?
事务在执行的过程中难免会发生某些意外:
上述这些情况,都会导致事务执行一般就结束,但是事务在执行过程中已经修改了很多数据,为了保证事务的原子性,我们必须改回原来的样子。
数据库的回滚操作和悔棋类似,如果向数据库中插入了一条数据,对应的回滚操作就是把这条记录删除掉,更新了一条记录,对应的回滚操作就是把该记录更新回旧值;
因此,每当对一条记录进行改动的时候,都需要将回滚所需的东西记录下来,
MySQL中规定,把用来记录事务回滚时所需信息的日志称为undo日志,由于select不会对记录进行改动,所以进行select操作时,不用记录undo日志.
如果某个事务在执行过程中对某个表执行了增删改操作,那么InnoDB存储引擎会为该事务分配一个独一无二的事务id,对于只读事务来说,只有在它对用户创建的临时表进行增删改查操作时,才会为该事务分配一个事务id,否则不会分配;
roll pointer作为用户记录的隐藏列,本质上是一个指向记录对应的undo日志的指针
trx_id保存的是,对该条聚簇索引记录进行改动的语句所在的事务id
在某些更新操作中,一条更新语句,可能对应多条undo日志,这些日志从0编号,被放在类型为FIL_PAGE_UNDO_LOG的页面中。
向页面中插入的记录会根据记录头信息中的next_record属性组成一个单向链表,同样,被删除的记录也会根据记录的头信息中的next_record组成一个链表,只不过在该链表中的记录占用的空间可以被覆盖,所以也称为垃圾链表
通过delete语句删除一条记录分为以下两个阶段:
在执行update语句时,InnoDB在对更新主键和不更新主键采取两种不同的方案
不更新主键的情况中也可分为被更新列占用的存储空间是否发生变化两种情况
(1)当被更新列占用的存储空间不发生变化时,采用就地更新的方式
(2)当被更新列占用的存储空间发生变化时,会先删除旧纪录,再插入新纪录,这里所说的删除不是delete mark,而是真正的删除
更新主键的情况
在聚簇索引中,记录之间根据主键进行排序,如果我们将索引从1更新成10000,并且在1-10000之间还有很多记录,此时主键值为1的记录和主键值为10000的记录之间会离的很远,对于这中情况,InnlDB分两步处理:
第一步:对旧纪录进行delete mark操作,记录一条类型为 TRX_UNDO_DEL_MARK_REC的undo 日志
第二步:插入一条新的记录到聚簇索引中,记录一条类型为TRX_UNDO_INSERT_REC的undo日志
也就是说,对更新一条记录的主键值时,会生成两条undo日志
在一个事务中,可能包含多个语句 ,所以在一个事务中可能产生很多的undo日志,这些日志可能一个页面中放不下,需要放到多个页面中,多个页面形成一个链表
InnoDB中规定,同一个undo页面中,要么只存储TRX_UNDO_INSERT大类的undo日志,要么只存储TRX_UNDO_UPDATE大类的undo日志,不能混着存,所以一个事务在执行过程中,需要2个undo页面的链表
InnoDB中规定,每个Undo页面链表都对应着一个段,称为Undo Log Segment,链表中的页面都是从这个段中申请的,
Undo页面链表的第一个页面比普通页面多了一个Undo Log Segment Header
TRX_UNDO_STATE:当前页面链表处于什么状态
TRX_UNDO_LOG:Undo页面链表中最后一个Undo Log Header 的位置
TRX_UNDO_FSEG_HEADER:本Undo 页面链表对应的段的Segment Header信息
TRX_UNDO_PAGE_LIST:Undo页面链表的基节点
一个事务在向Undo页面中写入undo日志时,采用的方式很简单,直接往里"堆",写完一个Undo页面后,再从段中申请一个新页面
InnoDB中规定,同一事务向一个Undo页面链表中写入的undo日志算是一组
Undo Log Header 的结构:
TRX_UNDO_TRX_ID:生成本组undo日志的事务id
TRX_UNDO_TRX_NO:事务提交后生成的第一个序号
TRX_UNDO_DEL_MARKS:标记本组undo日志中是否包含由delete mark操作产生的undo 日志
TRX_UNDO_LOG_START:标记本组日志中第一条undo日志在页面中的偏移量
TRX_UNDO_NEXT_LOG:下一组undo日志在页面中开始的偏移量
TRX_UNDO_PREV_LOG:上一组undo日志在页面中开始的偏移量
一个事务在执行的过程中最多可以分配4个Undo页面链表,因此同一时刻可以存在多个Undo页面链表,为了更好的管理这些Undo页面链表,InnoDB设计了一个名为Rollback Segment Header的页面,在这个页面中存放了各个Undo页面链表的first undo page的页号,这些页号称为undo slot
每一个Rollback Segment Header属于一个Rollback Segmeng段,同时,这个回滚段中其实只有一个页面
TRX_RSEG_MAX_SIZE:这个回滚段中所有undo链表中的所有undo页面之和的最大值
TRX_RSEG_HISTORY_SIZE:History链表占用的页面数量
TRX_RSEG_HISTORY:History链表的基节点
TRX_RSEG_FSEG_HEADER:这个回滚段对应的10字节大小的Segment Header结构
TRX_RSEG_UNDO_SLOTS:各个undo页面链表的first undo page的页号集合
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。