MVCC

功能

通过维护数据历史版本,从而解决并发情况下的读一致性问题。

核心内容

主要包含了:

  • 版本链:每一个数据行包含两个隐藏数据,事务id和回滚指针,将每一次更改通过回滚指针连起来。
  • 事务链表:事务开始的时候,就会加入事务链表。提交后,就会在事务链表中删除。
  • ReadView:一个事务在开始执行SQL的时候,会先创建一个ReadView。该ReadView存储着事务链表。通过判断要访问的事务是否在ReadView中,从而判断该事务里的数据该不该读。
    preview

版本链

每一个数据行有两个隐藏的数据列(实际上,如果数据行没有主键且没有唯一列,InnoDB除了以上两个以外,还会新建一个隐藏列作为索引主键):

  • trx_id(事务id)
  • roll_pointer(回滚指针)
    假设hero表中只有一行记录,当时插入的事务id为80。此时,该条记录的示例图如下:

img

假设之后两个事务id分别为100200的事务对这条记录进行UPDATE操作,操作流程如下:

img

由于每次变动都会先把undo日志记录下来,并用roll_pointer指向undo日志地址。因此可以认为,对该条记录的修改日志串联起来就形成了一个版本链,版本链的头节点就是当前记录最新的值。如下:

img

事务链表

MySQl中的事务在开始到提交的时候都会存进事务链表中。用来表示当前活跃的事务。 一旦提交就会从事务链表中清除。
img

ReadView

preview

  • 参数
    • trx_ids:用来表示当前活跃的事务
    • up_trx_id:trx_ids中的最大值
    • low_trx_id:trx_ids中的最小值
    • creator_trx_id:创建该ReadView的事务id
  • 描述
    一个事务在开始执行SQL语句的时候,会创建一个ReadView。有了ReadView之后,就可以判断某个版本的记录是否对当前事务可见。
    • 被访问的记录trx_id与creator_trx_id相同:可以访问。
    • 被访问的记录trx_id小于low_trx_id:说明已经提交,可以访问。
    • 被访问的记录trx_id大于等于up_trx_id:可能是在创建ReadView之后,提交情况未知,不可访问。
    • 被访问的记录trx_id在low_trx_id和ip_trx_id之间
      • 如果在trx_ids中,说明未提交,不可访问
      • 如果不在trx_ids中,说明已经提交,可以访问

MVCC与隔离级别

参考MySQL事务隔离级别和MVCC

  • Read Committed:在每一次select的时候,会创建readview表。当要访问某个数据的时候,先去查看该数据行的版本链,
    • 如果最新的版本链的事务id小于readview的low_trx_id,那么表示最近修改该数据行的事务已经提交,可以访问;
    • 如果大于readview的max_trx_id,那么不可以访问,顺延回滚指针查看更老的版本数据行;
    • 如果在readview trx_ids里,那么说明该事物活跃,不可以访问,顺延回滚指针;
    • 如果在(low_trx_id, up_trx_id)范围里,且不在m_id,说明该事务已经提交,可以访问。
  • Repeatable Read:只在第一次读的时候,生成一个ReadView,即使readview范围里,有事务提交了,也不会去读,从而保证了,读到的数据前后一致性。
  • 在Repeatable Read事务机制下,使用Next-Key Lock(锁定一个范围) 可以解决幻读。
    • 对于快读,select,可以直接使用mvcc的特性进行读;
    • 对于当前读,增删改,那么就需要使用Next-Key Lock加锁。也就是当一个事务1正在select一个事务的时候,会对相应的查找范围加一个next-key的锁,当事务2想要对这个范围的加入新的数据行是会被拒绝的。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值