图解 MySQL 事务和MVCC多版本并发控制

MySQL事务隔离级别

未提交读

事务中的修改,即便是没有提交,对其他事务也是可见的。

可能会产生脏读、不可重复读、幻读问题。

脏读示例:

图解 MySQL 事务和MVCC多版本并发控制_第1张图片

 已提交读

一个事务开始时,只能“看见”已经提交的事务所做的修改。

可能会产生不可重复读、幻读问题。

不可重复读示例:

图解 MySQL 事务和MVCC多版本并发控制_第2张图片

可重复读 

保证了同一个事务中多次读取同样记录的结果是一致的。

可能造成幻读问题。

幻读示例:

图解 MySQL 事务和MVCC多版本并发控制_第3张图片

 可串行化

是最高的隔离级别,它通过强制事务串行执行,避免了前面所说的幻读问题。简单来说,它会在读取的每一行数据上都加锁,所以可能导致大量的超时和锁争用的问题。

图解 MySQL 事务和MVCC多版本并发控制_第4张图片

MVCC多版本并发控制

MySQL 的大多数事务型存储引擎实现的都不是简单的行级锁。基于提升并发性能的考虑,它们一般都同时实现了多版本并发控制(MVCC)。

可以认为MVCC是行级锁的一个变种,但是它在很多情况下避免了加锁操作,因此开销更低。虽然实现机制有所不同,但大都实现了非阻塞的操作,操作也只锁定必要的行。

MVCC是一种读-写并发的解决方案。

InnoDB 的MVCC,在每个记录后面保存两个隐藏的列来实现的:

    创建时间:系统版本号(事务ID)

    过期时间(删除时间):系统版本号(事务ID)

每开始一个新的事务,系统版本号都会自动递增。

事务开始时刻的系统版本号会作为事务的版本号,也就是事务ID。

例如,表T1:

    事务1(事务ID:1)插入两条数据,并提交:

id name 隐藏列:创建时间 隐藏列:过期时间(删除时间)
1 n1 1 undefined
2 n2 1 undefined

SELECT

    会根据以下两个条件检查每行记录:

        a、只查找版本早于当前事务版本的数据行。

        b、行的删除版本要么未定义,要么大于当前事务版本号。

INSERT

    为新插入的每一行保存当前系统版本号作为行版本号(事务ID)。

DELETE

    为删除的每一行保存当前系统版本号作为行删除标识。

UPDATE

     插入一行新记录,保存当前系统版本号作为行版本号,同时保存当前系统版本号到原来的行作为行删除标识。

例:

 为了表示MVCC的工作流程,我画了一张很大很大的图:

图解 MySQL 事务和MVCC多版本并发控制_第5张图片

解释一下:

1、事务2 先开始执行,(为啥它先开始执行?因为它的事务ID小啊,小的当然是先执行的)

2、事务2 开始后,还未执行查询

       事务3 开始执行:

             插入id为3的行

             删除id为2的行

             更新id为1的行

             3行数据全部发生改变,创建时间和过期时间列也相应改变。

      事务3 结束 (不一定在事务2结束前结束)

3、事务2 执行查询:

    当前表最新数据已经变化,但事务2 查询的是 事务开始时的快照,也就是系统版本为2时的数据。

4、事务2 结束

 

有不对的地方,或困惑的地方,请指正。

你可能感兴趣的:(学习笔记)