数据库——mvcc

 

一、基本概念

mvcc是multi-version concurrency control(多版本并发控制)的英文缩写,它是现代数据库解决高并发读写场景时,提供高性能的一种并发控制方式,相当于一种数据库乐观锁的实现方式。这里的多版本是指同一数据会存在多条拷贝,即多个版本,这些版本构成一条版本链,而每个事务只能看到其中的某个合理的版本号数据。

二、适用范围

mvcc适用于数据库两种事务隔离级别,即读已提交和可重复读,而mvcc与读未提交和串行化不兼容。另外两种事务隔离界别,读未提交,由于可以读取到其他事务的未提交数据,即最新版本的数据,所以不需要做版本控制;而串行化,直接锁表或锁定读写的数据行,不存在并发读写同一数据的情况,所以也不需要做并发控制。

三、实现方式

在mysql数据的innodb存储引擎下,每个表都隐含三个隐藏列,其中两个与mvcc有关(第三个是db_row_id,当表没有主键时,会自动生成一列隐藏主键列,大小6字节),即

  • 数据行版本号:db_trx_id,记录最近更新这条数据或插入数据的事务id,大小6字节
  • 回滚指针:db_roll_ptr,指向该行数据的上一个版本数据的地址,大小7字节。所有旧版本数据在undo log中以链表的形式组织在一起。

每当开启一个事务时,数据库系统版本号会递增,而事务会获取这个版本号作为这个事务的id。根据mvcc的查询规则,个人推测系统版本号是随着新建事务的时间顺序,单调递增的。

1.insert操作

插入数据时,数据行版本号记录当前事务id,回滚指针是null。

2.update操作

修改数据时,先把旧版本数据复制到undo log中,再修改当前数据,并标记数据行版本号为当前事务id,回滚指针记录复制到undo log中的旧版本数据地址

3.delete操作

删除数据时,修改数据头部信息中deleted_flag,表示被删除,当提交时,才删除。

4.select操作

查询数据时,会比较当前事务id和数据的数据行版本号,并结合可读视图来确定哪些数据可见。

  • 数据行版本号小于当前事务id,说明是当前事务开启前就提交的数据,因此可以查询到;数据行版本号等于当前事务id,说明是当前事务插入或修改的数据,因此也可以查询到。
  • (关于删除版本号的概念和作用,有待进一步研究)删除版本号是null,说明是未删除数据,因此可以查询到;删除版本号小于当前事务id,说明是当前事务开启前就被删除的数据,因此不会被查询到;删除版本号等于当前事务id,说明是当前事务删除的数据,因此不会被查询到;删除版本号大于当前事务id,说明是当前事务开启后后续事务删除的数据,相当于时在未来删除的数据,因此在当前事务中还是可以查询到的。

四、可读视图readview

可读视图是在读已提交或可重复读隔离级别下,判断哪些数据可以返回的一个工具,它包含了当前事务执行时,数据库中所有活跃事务的id。

在读已提交隔离级别时,一个事务中每次select前,都会生成一份新的可读视图。因为这期间可能有其他事务提交或开启,所以每次的readview可能不同。而可重复读隔离级别时,只有在第一次select前才生出可读视图,后面的多次select都使用同样的可读视图。

当查询数据时,会比较数据的行版本号和当前事务可读视图。

  • 如果数据行版本号小于可读视图中最小的事务id,说明该版本数据在当前事物开启前就已经提交,因此可以查看。
  • 如果数据行版本号大于可读视图中最大的事务id,说明修改该版本数据的事务开启时间晚于当前事务开启,即相当于是被未来时间的事务修改的,因此不可以查看。那么会根据回滚指针,在undo log的版本链中,查找上一版本数据,再进行同样的比较,直到找到符合条件的版本数据。
  • 如果数据行版本号介于可读视图中最大的事务id和最小事务id之间,那么需要比较是否存在与可读视图中。如果存在,说明修改数据的事务还没有提交,那么不可以查看。如果不存在,说明已经提交,那么可以查看。

 

更多讲解,可参考以下博客

https://juejin.im/post/5c68a4056fb9a049e063e0ab

https://www.jianshu.com/p/f692d4f8a53e

https://draveness.me/database-concurrency-control/

https://zhuanlan.zhihu.com/p/64576887

 

 

你可能感兴趣的:(数据库,mysql)