MVVC 的实现原理
MVVC 有什么用
间隙锁
还是最开始更新用户年龄的例子,如果 id = 49 这条记录不存在,这个 SQL 语句还会加锁吗?答案是可能有,这取决于数据库的隔离级别。这种状况下,在 RC 隔离级别不会加任何锁,在 RR 隔离级别会在 id = 49 前后两个索引之间加上间隙锁。
间隙锁是一种加在两个索引之间的锁,或者加在第一个索引之前,或最初一个索引之后的间隙。这个间隙能够跨一个索引记录,多个索引记录,甚至是空的。应用间隙锁能够避免其余事务在这个范畴内插入或批改记录,保障两次读取这个范畴内的记录不会变,从而不会呈现幻读景象。
值得注意的是,间隙锁和间隙锁之间是互不抵触的,间隙锁惟一的作用就是为了避免其余事务的插入,所以加间隙 S 锁和加间隙 X 锁没有任何区别。
Next-Key 锁
Next-key 锁是记录锁和间隙锁的组合,它指的是加在某条记录以及这条记录后面间隙上的锁。假如一个索引蕴含 15、18、20,30,49,50 这几个值,可能的 Next-key 锁如下:
(-∞, 15],(15, 18],(18, 20],(20, 30],(30, 49],(49, 50],(50, +∞)
通常咱们都用这种左开右闭区间来示意 Next-key 锁,其中,圆括号示意不蕴含该记录,方括号示意蕴含该记录。后面四个都是 Next-key 锁,最初一个为间隙锁。和间隙锁一样,在 RC 隔离级别下没有 Next-key 锁,只有 RR 隔离级别才有。还是之前的例子,如果 id 不是主键,而是二级索引,且不是惟一索引,那么这个 SQL 在 RR 隔离级别下就会加如下的 Next-key 锁 (30, 49](49, 50)
此时如果插入一条 id = 31 的记录将会阻塞住。之所以要把 id = 49 前后的间隙都锁住,依然是为了解决幻读问题,因为 id 是非惟一索引,所以 id = 49 可能会有多条记录,为了避免再插入一条 id = 49 的记录。
幻读
1:幻读是什么?幻读有什么问题?如何防止?
幻读我的了解是,读出的数据呈现了不统一的景象,在事务的读未提交和读已提交这两种事务的隔离级别下会呈现幻读的景象,问题嘛?就是数据不统一了,对于数据严格要求统一的场景是不可能容许的。如何防止?在可反复读和串行化的事务隔离级别下应该不会呈现
课后思考
1:学完此节后发现自己的认知,根本是错的
1-1:什么是幻读?
幻读是指在同一个事务中,存在前后两次查问同一个范畴的数据,然而第二次查问却看到了第一次查问没看到的行。
留神,幻读呈现的场景
第一:事务的隔离级别为可反复读,且是以后读
第二:幻读仅专指新插入的行
1-2:幻读带来的问题?
一是,对行锁语义的毁坏
二是,毁坏了数据一致性
1-3:怎么防止幻读?
存储引擎采纳加间隙锁的形式来避免出现幻读
1-4:为啥会呈现幻读?
行锁只能锁定存在的行,针对新插入的操作没有限定
1-5:间隙锁是啥?它怎么避免出现幻读的?它引入了什么新的问题?
间隙锁,是专门用于解决幻读这种问题的锁,它锁的了行与行之间的间隙,可能阻塞新插入的操作
间隙锁的引入也带来了一些新的问题,比方:升高并发度,可能导致死锁。
留神,读读不互斥,读写 / 写读 / 写写是互斥的,然而间隙锁之间是不抵触的,间隙锁会阻塞插入操作
另外,间隙锁在可反复读级别下才是无效的
MVCC 真的解决了幻读?
从最开始咱们的测试示例和下面的实践反对来看貌似在 MySQL 中通过 MVCC 就解决了幻读的问题,那既然这样串行化读貌似就没啥意义了,带着疑难持续测试。
测试前数据:
事物 1 | 事物 2 |
---|---|
begin | begin |
select * from dept | |
– | insert into dept(name) values(“ 研发部 ”) |
– | commit |
update dept set name=” 财务部 ”(工作中如果不想被解雇肯定要写 where 条件) | |
commit |
依据下面的后果咱们冀望的后果是这样的:
id name
1 财务部
2 研发部
然而实际上咱们的通过是:
原本咱们心愿失去的后果只是第一条数据的部门改为财务,然而后果的确两条数据都被批改了。这种后果通知咱们其实在 MySQL 可反复读的隔离级别中并不是齐全解决了幻读的问题,而是解决了读数据状况下的幻读问题。而对于批改的操作仍旧存在幻读问题,就是说 MVCC 对于幻读的解决时不彻底的。
执行 update 时以非索引字段作为查问条件会有什么问题?
对于非索引字段进行 update 或 select .. for update 操作,代价极高。所有记录上锁,以及所有距离的锁。
对于索引字段进行上述操作,代价个别。只有索引字段自身和左近的距离会被加锁。
所以 update、delete 语句用不上索引是很恐怖的