14、多版本并发控制
多版本并发控制
什么是MVCC
1、多版本并发控制(MVCC)解决了脏读、不可重复读、幻读的问题,保证了事务的隔离性,实现了数据的一致性读,。
2、MVCC实现依赖于
- 隐藏字段(trx_id、roll_pointer)、undo log:实现了多版本
- readview:实现了并发控制
快照读和当前读
2.1快照读
- 快照读又叫一致性读,读取的是历史版本的数据。不加锁的简单的SELECT都属于快照读,即不加锁的非阻塞读。
- 快照读的实现是基于MVCC,它在很多情况下,避免了加锁操作,降低了开销,提高了数据库的并发性能。
2.2当前读
- 当前读读取的是记录的最新数据。加锁的SELECT、对数据进行增删改都会进行当前读。
- 当前读的实现是基于锁,读取时其他并发事务不能修改和读取当前记录。
隐藏字段和undo log版本链
3.1隐藏字段
对于使用InnoDB存储引擎的表来说,它的聚簇索引记录中都包含两个必要的隐藏列。
- trx_id :每次一个事务对某条聚簇索引记录进行改动时,都会把该事务的 事务id赋值给trx_id 隐藏列。
- roll_pointer :每次对某条聚簇索引记录进行改动时,都会把旧的版本写入到undo日志中,然后这个隐藏列就相当于一个指针,可以通过它来找到该记录修改前的信息。
insert undo log只在事务回滚时起作用;当事务提交后,该类型的undo日志就会被删除,它占用的UndoLog Segment也会被系统回收。
update undo log用于进行事务的回滚;当事务提交后该日志就会放入undo log版本链中用于实现MVCC。
3.2undo log版本链的生成
- 两个事务id分别为10、20的事务对id为1的记录进行UPDATE操作。
- 对该记录每次更新后,都会将旧值放到一条undo日志中,每条undo日志也都有一个roll_pointer属性,roll_pointer属性连接成一个undo log版本链。
readview
4.1什么是readview
readview就是事务在使用MVCC机制进行快照读操作时产生的读视图。使用readview可以实现对undo log版本链的控制。
4.2readview的组成
MVCC只能在READ COMMITTED和REPEATABLE READ隔离级别下使用,可以读取到已经提交的数据,对未提交的数据是不可读的。
readview中包含的内容:
- creator_trx_id:创建这个Read View的事务ID。
只有在对表中的记录做改动时(执行INSERT、DELETE、UPDATE这些语句时)才会为事务分配事务id,否则在一个只读事务中的事务id值都默认为0。
- trx_ids:表示在生成ReadView时当前系统中活跃的读写事务的事务id列表 。
- up_limit_id:活跃的事务中最小的事务ID。
- low_limit_id:表示生成ReadView时系统中应该分配给下一个事务的id值。(系统中最大的事务id加上1就是low_limit_id)
low_limit_id并不是trx_ids中的最大值,事务id是递增分配的。比如,现在有id为1,2,3这三个事务,之后id为3的事务提交了。那么一个新的读事务在生成ReadView时,trx_ids就包括1和2,up_limit_id的值就是1,low_limit_id的值就是4。
4.3readview的规则
这样在访问某条记录时,只需要按照下边的步骤判断记录的某个版本是否可见:
- 如果被访问版本的trx_id属性值与ReadView中的creator_trx_id值相同,意味着当前事务在访问它自己修改过的记录,所以该版本可以被当前事务访问。
- 如果被访问版本的trx_id属性值小于ReadView中的up_limit_id值,表明生成该版本的事务在当前事务生成ReadView前已经提交,所以该版本可以被当前事务访问。
- 如果被访问版本的trx_id属性值大于或等于ReadView中的low_limit_id值,表明生成该版本的事务在当前事务生成ReadView后才开启,所以该版本不可以被当前事务访问。
- 如果被访问版本的trx_id属性值在ReadView的up_limit_id和low_limit_id之间,那就需要判断一下trx_id属性值是不是在trx_ids列表中:
如果在,说明创建ReadView时生成该版本的事务还是活跃的,该版本不可以被访问。
如果不在,说明创建ReadView时生成该版本的事务已经被提交,该版本可以被访问。
4.4readview的生成时机
READ COMMITTD和REPEATABLE READ这两个隔离级别的一个很大不同就是生成ReadView的时机不同:
-
READ COMMITTD:在每一次进行普通SELECT操作前都会生成一个ReadView
-
REPEATABLE READ:只在第一次进行普通SELECT操作前生成一个ReadView,之后的查询操作都重复使用第一次的ReadView就好了。
4.5MVCC操作的整体流程
查询一条记录:
- 首先获取事务自己的版本号,也就是事务 ID;
- 获取该事务的ReadView;
- 查询得到的数据的事务id,然后与ReadView的规则进行比较;
- 如果不符合ReadView规则,就需要从Undo Log版本链中获取下一个版本的数据;
- 最后返回符合规则的数据。