(十二)MVCC

MVCC:多版本并发控制技术。保存数据的历史版本。这样我们就可以通过比较版本号决定数据是否显示出来。

InnoDB中的RC和RR隔离事务是基于多版本并发控制(MVCC)实现高性能事务。一旦数据被加上排他锁,其他事务将无法加入共享锁,且处于阻塞等待状态,如果一张表有大量的请求,这样的性能将是无法支持的;MVCC对普通的 Select 不加锁,如果读取的数据正在执行Delete或Update操作,这时读取操作不会等待排它锁的释放,而是直接利用MVCC读取该行的数据快照。

事务版本号

每开启一个事务,我们都会从数据库中获得一个事务ID(也就是事务版本号),这个事务ID是自增长的,通过ID大小,我们就可以判断事务的时间顺序。

InnoDB的叶子节点存储的内容

  • row_id:隐藏的行ID,用来生成默认聚集索引。如果我们创建数据表的时候没有指定聚集索引,这时InnoDB就会用这个隐藏ID来创建聚集索引。采用聚集索引的方式可以提升数据的查找效率。
  • trx_id:操作这个数据的事务ID,也就是最后一个对该数据进行更新的事务ID
  • roll_ptr:回滚指针,也就是指向这个记录的Undo Log信息

Undo log

InnoDB将行数据快照保存在了Undo Log里。回滚指针将数据行的所有快照记录都通过链表的结构串联了起来,每个快照的记录都保存了当时的trx_id,也是那个时间点操作这个数据的事务ID。这样如果我们想要找历史快照,就可以通过遍历回滚指针的方式进行查找。

Read View

read view可以解决行的可见性。Read View是一个数组,由小到大保存了当前事务开启时所有还没有提交的事务列表,即不应该让这个事务看到的其他的事务ID列表。

当前有事务creator_trx_id想要读取某个行记录,这个行记录在叶子节点中的事务ID为trx_id,那么会出现以下几种情况:

  • 行记录trx_id < Read View中最小的事务id,也就是说这个行记录所在的事务在当前事务所在的所有活跃的事务创建之前就已经提交了,那么这个行记录对该事务是可见的
  • 行记录trx_id > Read View中最大的事务id,也就是说这个行记录所在的事务在当前事务所在的所有活跃的事务创建之后提交的,那么这个行记录对该事务是不可见的
  • 如果up_limit_id < trx_id < low_limit_id,说明该行记录所在的事务trx_id在目前creator_trx_id这个事务创建的时候,可能还处于活跃的状态,因此我们需要在trx_ids集合中进行遍历,如果trx_id存在于trx_ids集合中,证明这个事务trx_id还处于活跃状态,不可见。否则,如果trx_id不存在于trx_ids集合中,证明事务trx_id已经提交了,该行记录可见。

MVCC下查询一条记录:

InnoDB中,MVCC是通过Undo Log + Read View进行数据读取,Undo Log保存了历史快照,而Read View规则帮我们判断当前版本的数据是否可见。

  1. 首先获取事务自己的版本号,也就是事务ID;
  2. 获取当前事务的Read View;
  3. 查询行数据的事务id,然后与Read View中的事务版本号进行比较;
  4. 如果不符合ReadView规则,就需要从Undo Log中获取历史快照;
  5. 最后返回符合规则的数据。

读已提交实现机制:

在隔离级别为读已提交(Read Commit)时,一个事务中的每一次SELECT查询都会获取一次Read View,同样的查询语句都会重新获取一次Read View,这时如果Read View不同,就可能产生不可重复读或者幻读的情况。

可重复读实现机制:

当隔离级别为可重复读的时候,事务只在第一次SELECT的时候会获取一次Read View,而后面所有的SELECT都会复用这个Read View,这样就能同一事务读取数据不一致的情况。

InnoDB三种行锁的方式:

  • 行锁(记录锁):针对单个行记录添加锁。
  • 间隙锁(Gap Locking):可以帮我们锁住一个范围(索引之间的空隙),但不包括记录本身。采用间隙锁的方式可以防止幻读情况的产生。
  • Next-Key锁:帮我们锁住一个范围,同时锁定记录本身,相当于间隙锁+记录锁,可以解决幻读的问题。

InnoDB幻读解决机制:

InnoDB可以通过Next-Key锁+MVCC来解决幻读问题。InnoDB事务中,通过Next-Key锁住事务读取的范围,解决幻读情况。

例如:事务的读取height> 2.08 , Next-key将锁住heiht>2.08的部分,这样其他事务想要插入时就会失败,解决幻读问题。

posted @ 2022-08-24 17:19  言思宁  阅读(48)  评论(0编辑  收藏  举报