所谓的 MVCC (Multi-Version Concurrency Control ,多版本并发控制)指的就是在使用 READ COMMITTD 、 REPEATABLE READ 这两种隔离级别的事务在执行普通的 SEELCT 操作时访问记录的版本链的过程,这样子可以使不同事务的 读-写 、 写-读 操作并发执行,从而提升系统性能。
版本链
聚簇索引记录中的两个关键的隐藏列
trx_id :对某条记录修改时 会把事务id拿给trx_id
roll_pointer :指向这条记录被修改之前的undo日志记录
更新次数增多,所有属性被roll_pointer连接成一个链表,即为版本链。 其中链表头节点就是当前的最新值
ReadView
read committed和repeatable read必须保证读取的是已经提交过了修改的记录
一个事务已经修改了记录但是没有提交,是不能直接读取版本的最新记录的 怎么办?
所以需要判断版本链中哪个版本是当前事务可见的
所以使用ReadView
其中关键属性
-
m_ids :表示在生成 ReadView 时当前系统中活跃的读写事务的 事务id 列表。(意思提交之后就被移除)
-
min_trx_id :表示在生成 ReadView 时当前系统中活跃的读写事务中最小的 事务id ,也就是 m_ids 中的最 小值。
-
max_trx_id :表示生成 ReadView 时系统中应该分配给下一个事务的 id 值。
-
creator_trx_id :表示生成该 ReadView 的事务的 事务id 。
有了ReadView之后改如何判断呢?
判断规则如下
-
如果被访问版本的 trx_id 属性值与 ReadView 中的 creator_trx_id 值相同,意味着当前事务在访问它自己 修改过的记录,所以该版本可以被当前事务访问。
-
如果被访问版本的 trx_id 属性值小于 ReadView 中的 min_trx_id 值,表明生成该版本的事务在当前事务生 成 ReadView 前已经提交,所以该版本可以被当前事务访问。
-
如果被访问版本的 trx_id 属性值大于 ReadView 中的 max_trx_id 值,表明生成该版本的事务在当前事务生 成 ReadView 后才开启,所以该版本不可以被当前事务访问。
-
如果被访问版本的 trx_id 属性值在 ReadView 的 min_trx_id 和 max_trx_id 之间,那就需要判断一下 trx_id 属性值是不是在 m_ids 列表中,如果在,说明创建 ReadView 时生成该版本的事务还是活跃的,该 版本不可以被访问;如果不在,说明创建 ReadView 时生成该版本的事务已经被提交,该版本可以被访问。
就是要跟到链表走 链表trx_id<readView中min_trx_id属性就说明该版本可以被访问。(因为min_trx_id 是活跃的最小事务id)
总结
read committed每次只要查询都会生成一个ReadView ,repeatable read在查询的时候只生成一次ReadView
所以 repeatable read即使在一个事务在第一次查询之后,有其他事务指向修改操作并提交,然后第一个事务再查询的时候也是最初的值。
所以这样可以让多个事务 读–写,写–读操作能够并发执行。