MySQL事务隔离级别
未提交读
事务中的修改,即便是没有提交,对其他事务也是可见的。
可能会产生脏读、不可重复读、幻读问题。
脏读示例:
已提交读
一个事务开始时,只能“看见”已经提交的事务所做的修改。
可能会产生不可重复读、幻读问题。
不可重复读示例:
可重复读
保证了同一个事务中多次读取同样记录的结果是一致的。
可能造成幻读问题。
幻读示例:
可串行化
是最高的隔离级别,它通过强制事务串行执行,避免了前面所说的幻读问题。简单来说,它会在读取的每一行数据上都加锁,所以可能导致大量的超时和锁争用的问题。
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的工作流程,我画了一张很大很大的图:
解释一下:
1、事务2 先开始执行,(为啥它先开始执行?因为它的事务ID小啊,小的当然是先执行的)
2、事务2 开始后,还未执行查询
事务3 开始执行:
插入id为3的行
删除id为2的行
更新id为1的行
3行数据全部发生改变,创建时间和过期时间列也相应改变。
事务3 结束 (不一定在事务2结束前结束)
3、事务2 执行查询:
当前表最新数据已经变化,但事务2 查询的是 事务开始时的快照,也就是系统版本为2时的数据。
4、事务2 结束
有不对的地方,或困惑的地方,请指正。