数据库MVCC总结

为何须要MVCC

当多个数据库事务同时运行,其修改数据产生的中间状态对于其余事务的可见性是数据库隔离级别来限制的,而这个可见性的约束有四种sql

  • 读未提交
  • 读已提交
  • 可重复读
  • 串行化

其中读未提交最弱,多个事务共享一份数据就行了,而串行化最强,读取加读锁,写数据加写锁,而读已提交和可重复读都须要有“不读取未提交的数据”和“只读取建立事务以前的数据”这样的需求,而实现这样的需求,天然而然的想到要引入“快照”的概念,也就是对数据库的每一行,并发修改的时候生成快照,在MySQL,快照的实现借助的是MVCC,即多版本并发控制,下面将主要围绕快照如何组织,以及如何使用快照两个部分对MVCC进行描述。数据库

快照如何组织?

MySQL的快照依赖的是版本链,也就是UndoLog,UndoLog在每次修改数据的时候,保留数据最初始的版本,同时记录最新版,既然是链,就有指针,这个指针在每行数据的隐藏字段当中,同时,每次修改的快照天然须要记录是谁修改的,这个谁就是事务,事务有本身的惟一,自增的事务Id,惟一是标识事务的必要条件,而自增,则给了事务Id顺序性的含义,顺序的ID对于以后使用快照的阶段很是重要,固然事务Id和undo指针同样都在每行数据的隐藏字段当中。markdown

image.png 其中trx_id就是事务Id,roll_p就是指针并发

若是有一条记录为A,通过了以下的操做oop

事务2 事务3
begin;
将A修改成B begin;
将B修改成C(时刻1)
commit;
commit;

那么在时刻1的版本链以下所示:spa

image.png

如今版本链已经有了,可是如何使用,只靠一个版本链是缺少足够的信息来实现读已提交和可重复读的,咱们还缺少在事务建立的一些额外的信息,就比如,读已提交须要知道什么是已提交,进一步,哪些事务是已提交的,等等,这些信息构成了使用MVCC的运行时上下文,下面咱们总结下MVCC使用的上下文信息。线程

快照如何使用?

建立快照的时候也须要记录一些建立时刻的基本信息,好比建立事务的时刻,有哪些事务正在运行,这些数据方便界定哪些事务是已经提交了的,我能够读了,也须要当前事务的事务Id,也须要在建立快照的那一刹那,标识对于当前的事务而言,哪些事务对于当前的事务是不可见的将来。对于这些数据,以下图所示:指针

image.png

其中m_ids表示建立事务的那一刻,当前运行中的事务,creator_trx_id表示建立者事务,min_trx_idm_ids的最小值,小于min_trx_id的事务Id对当前事务而言是妥妥的已提交,而max_trx_id是当前事务Id的下一个Id。code

快照如何工做,主要依赖以上描述的信息搭配undoLog链:orm

  • 若是访问undolog版本的trx_id属性值creator_trx_id相同,则是本身的记录,可见
  • 若是trx_id小于min_trx_id则表明该记录已经提交,可见
  • 若是trx_id大于等于max_trx_id则是建立该视图以后的事务,不可见
  • 若是trx_id处于min_trx_idmax_trx_id之间,则须要判断此时此刻trx_id是否在m_ids之间,若是依然在,则不可见。

读已提交和可重复读的区别

上面描述的基本信息包含在一次读视图中(ReadView)

  • 对于读提交,是每次读操做都会建立新的视图,对于这种状况一个事务中读视图中的数据是不断变化的,所以每次能读取到最新的提交
  • 对于可重复读,是每次事务读的时候建立一个视图,而且一直沿用。

版本链什么时候清除

  • 后台运行Purge线程在什么时候的时候进行删除

注意事项

因为MVCC版本链的机制,可见为了支持MVCC,更新的数据能够和老数据同时留存,删除的数据也不会当即删除,而是打上删除标记,所以必定要注意长事务对于MySQL自己的影响

在开发过程当中,能够设置set autocommit=1

查询长事务能够经过以下的语句来查看:

select
    * 
from information_schema.innodb_trx
where 
TIME_TO_SEC(timediff(now(),trx_started))>60
复制代码

参考资料

掘金小册 极客时间

相关文章
相关标签/搜索