当多个数据库事务同时运行,其修改数据产生的中间状态对于其余事务的可见性是数据库隔离级别来限制的,而这个可见性的约束有四种sql
其中读未提交最弱,多个事务共享一份数据就行了,而串行化最强,读取加读锁,写数据加写锁,而读已提交和可重复读都须要有“不读取未提交的数据”和“只读取建立事务以前的数据”这样的需求,而实现这样的需求,天然而然的想到要引入“快照”的概念,也就是对数据库的每一行,并发修改的时候生成快照,在MySQL,快照的实现借助的是MVCC,即多版本并发控制,下面将主要围绕快照如何组织,以及如何使用快照两个部分对MVCC进行描述。数据库
MySQL的快照依赖的是版本链,也就是UndoLog,UndoLog在每次修改数据的时候,保留数据最初始的版本,同时记录最新版,既然是链,就有指针,这个指针在每行数据的隐藏字段当中,同时,每次修改的快照天然须要记录是谁修改的,这个谁就是事务,事务有本身的惟一,自增的事务Id,惟一是标识事务的必要条件,而自增,则给了事务Id顺序性的含义,顺序的ID对于以后使用快照的阶段很是重要,固然事务Id和undo指针同样都在每行数据的隐藏字段当中。markdown
其中
trx_id
就是事务Id,roll_p
就是指针并发
若是有一条记录为A,通过了以下的操做oop
事务2 | 事务3 |
---|---|
begin; |
|
将A修改成B |
begin; |
将B修改成C (时刻1) |
|
commit; |
|
commit; |
那么在时刻1的版本链以下所示:spa
如今版本链已经有了,可是如何使用,只靠一个版本链是缺少足够的信息来实现读已提交和可重复读的,咱们还缺少在事务建立的一些额外的信息,就比如,读已提交须要知道什么是已提交,进一步,哪些事务是已提交的,等等,这些信息构成了使用MVCC的运行时上下文,下面咱们总结下MVCC使用的上下文信息。线程
建立快照的时候也须要记录一些建立时刻的基本信息,好比建立事务的时刻,有哪些事务正在运行,这些数据方便界定哪些事务是已经提交了的,我能够读了,也须要当前事务的事务Id,也须要在建立快照的那一刹那,标识对于当前的事务而言,哪些事务对于当前的事务是不可见的将来。对于这些数据,以下图所示:指针
其中m_ids
表示建立事务的那一刻,当前运行中的事务,creator_trx_id
表示建立者事务,min_trx_id
是m_ids
的最小值,小于min_trx_id
的事务Id对当前事务而言是妥妥的已提交,而max_trx_id
是当前事务Id的下一个Id。code
快照如何工做,主要依赖以上描述的信息搭配undoLog链:orm
trx_id
属性值creator_trx_id
相同,则是本身的记录,可见trx_id
小于min_trx_id
则表明该记录已经提交,可见trx_id
大于等于max_trx_id
则是建立该视图以后的事务,不可见trx_id
处于min_trx_id
和max_trx_id
之间,则须要判断此时此刻trx_id
是否在m_ids
之间,若是依然在,则不可见。上面描述的基本信息包含在一次读视图中(ReadView)
因为MVCC版本链的机制,可见为了支持MVCC,更新的数据能够和老数据同时留存,删除的数据也不会当即删除,而是打上删除标记,所以必定要注意长事务对于MySQL自己的影响
在开发过程当中,能够设置set autocommit=1
查询长事务能够经过以下的语句来查看:
select
*
from information_schema.innodb_trx
where
TIME_TO_SEC(timediff(now(),trx_started))>60
复制代码