阅读本文需要了解undo log,mysql隔离级别,事务
MVCC
多版本并发控制,优点是读写分离,读写互相不阻塞,读取数据时不加锁。降低了死锁概率,同时极大提高了并发性能,是乐观锁的一种体现缺点是每行都要进行维护和检查工作。
实现细节
MVCC是通过在每行记录后面保存两个隐藏的列来实现的。一个是行的创建版本号,一个是行的删除版本号 ,以及一个指向历史版本链头节点的指针
每开始一个新的事务,事务都会分配一个递增事务的版本号,进行写操作后根据分配的事务版本号改变对应行的创建版本号和删除版本号;
进行读操作时需要如果行满足两个条件直接作为返回结果,否则就需要进行快照读也就是利用版本链指针读取存储在undo log版本链上的历史版本(**每一个历史版本都是一个链表节点,除了包含数据外以及指向下一个节点的指针外,还存在一个字段标注产生该历史版本的事务id)
-
事务版本号大于等于行的创建版本号,说明该行是在该事务创建之前就存在的,可作为结果
-
行的删除版本号要么未定义,要么大于当前版本号,说明是该改要么未被删除,要么是在事务执行之后才进行删除
每次开始事务时都会生成一个ReadView,ReadView中有个列表来存储我们系统中当前活跃的事务,也就是begin了还未提交的事务。通过ReadView可以判断历史版本链中的的某个版本是否已经被提交,从而决定是否采用该历史版本
如果历史版本的事务id小于ReadView中事务的最小id则说明该历史版本已经被提交,可以被访问
如果历史版本的事务id大于ReadView中事务的最大id,则说明该历史版本是在ReadView生成之后发生的,所以不能被访问
如果历史版本的事务id在ReadView列表事务id中,则表明该历史版本未被提交,不可访问,反之则表明已提交,可以被访问
而通过在一个事务中ReadView是否更新又可以实现不同的隔离级别。
在读已提交隔离级别下,每次读取数据都生成重新生成一个ReadView,这样就可以获取最新提交的版本
在可重复读隔离级别下,在第一次读取数据时生成ReadView之后复用,从而保证每次读取的版本都相同,实现可重复读