SQL|MVCC在重复读和读已提交场景以及幻读的解决

今天玩了下mysql感觉理解又深了一点
相关文章
(40条消息) MySQL可重复读隔离级别能解决幻读吗?_于你与你丶的博客-CSDN博客_mysql的可重复读能解决幻读吗
目录
首先:重复读和读已提交
【SQL|MVCC在重复读和读已提交场景以及幻读的解决】 索引失效造成的引伸:
然后我们聊聊读已提交和重复读
幻读:
MVCC是如何解决幻读的?
当前读作用
什么是next key lock?
宕机造成的影响


首先:重复读和读已提交
流程:1.首先是事务1进行事务开启,然后开启事务2——>2.事务1进行DML操作比如update某行数据——>3.然后切换到事务2,对事务1操作的数据再DML——>4.会发现事务2被阻塞了
总结:当表有索引,事务1对某行数据进行增删改,那么这行数据就会被上锁(行锁),当事务2对这行数据进行增删改就会出现阻塞(事务2操作其他行数据没事);
当表中没有索引,那么事务1对表中数据进行增删改的时候,整个表就会被上锁(也就是我们的表锁),当事务2进行增删改,无论表中是哪条数据都会被阻塞
SQL|MVCC在重复读和读已提交场景以及幻读的解决
文章图片

事务2的操作:SQL|MVCC在重复读和读已提交场景以及幻读的解决
文章图片

索引失效造成的引伸:
当第二个事务并没有操作事务操作的那行数据,而是操作其他数据时,按道理来说是被行锁所约束,所以说我们的事务2操作其他数据是不会被阻塞的,但是如果你是事务2用了!=,like这种造成索引失效——>就会导致阻塞,因为索引失效,那么就变成表锁级别了固然阻塞
SQL|MVCC在重复读和读已提交场景以及幻读的解决
文章图片

SQL|MVCC在重复读和读已提交场景以及幻读的解决
文章图片

然后我们聊聊读已提交和重复读
已提交和重复读其实都解决了脏读,重复读在此基础上解决了不可重复读的问题——>读已提交:事务1提交了后事务2才能读取事务1操作它更新的内容 ——>重复读:除了事务1要提交,事务2如果要读取最新数据也需要提交,不然读取不到最新数据
而不可重复读简单来说就是——>可能出现事务2在读取的时候,其他事务出现修改数据并且提交,那么我select的数据就发生了变化——>可重复读:利用select也要提交才能读取最新数据,防止了其他事务在select时候修改数据;——>(也体现出可重复读的隔离性之强)
幻读: 其实可重复读解决了我们的幻读问题,从引入MVCC就可以知道(MVCC实现了读已提交和可重复读)
什么是幻读:指的是在同一个事务里面连续执行两次相同的sql语句但是得到结果不同(这里指的是数据的行数发送变化,意思是被插入了)
MVCC是如何解决幻读的?
首先MVCC就是解决读写并发的,利用的是一个多版本的概念,引入三个隐藏字段以及undolog——>对数据进行回滚,成一个链式的数据链——>然后还引入了Read view(哪个版本的数据是可见的)
SQL|MVCC在重复读和读已提交场景以及幻读的解决
文章图片

像下面这种,我们就可以用快照读解决幻读问题——>就是利用我们的MVCC历史版本信息(快照)来获取可见数据
SQL|MVCC在重复读和读已提交场景以及幻读的解决
文章图片

其实像对数据进行修改的操作采用的都是当前读模式(insert/delete/update)
这些都是当前读——>获取最新的快照数据
1、select * from table where ? lock in share mode; (加共享锁)2、select * from table where ? for update; (加排它锁)

当前读作用
(40条消息) 快照读和当前读_是茜茜qianqian呀的博客-CSDN博客_快照读和当前读
在执行这几个操作时会读取最新的记录——>即时是别的事务提交的数据也可以查询到,比如:1.update一条记录,但是这条记录已经在另一个事务中被delete掉了并且commit——>2.这样就会起冲突,所以在update的时候需要知道最新的数据(读取的是最新的数据,并且需要加锁(排他锁或者共享锁))
举个例子,事务1在update后对该数据进行加锁,此时事务B肯定是无法加入新的数据的(因为我们事务A需要保证update数据前后一致),这时候可能会问我update只锁行数据啊(有索引的情况),其实实际上update锁不止锁查询的那几条语句,这样阻止不了insert,有的人会说锁整个表,那这样效率就会很低,我们用的是间隙锁(行锁+范围锁)
SQL|MVCC在重复读和读已提交场景以及幻读的解决
文章图片

什么是next key lock?
next key lock就是一个行锁(record lock)+范围锁(gap lock),比如某一个辅助索引(比如上面的class_id),如果它有1,3,5这几个值,那么当我们使用next key lock的锁住class_id=1的时候,实际上锁住了(-无穷,1],或者锁住class_id=3的时候,实际上锁住的是(1,3],也就是一个左开右闭的区间——>此时别的事务要在这个区间内插入数据,就会被阻塞住 ,这个锁一直到事务提交才会释放
注意:但是对于“唯一索引”,比如主键的索引,next key lock会降级成行锁,而不会锁住一个区间
因此,如果上面的事务1的update使用的是主键,事务2也使用主键进行插入,那么实际上事务2根本不会被阻塞,可以立即插入并返回。而对于非唯一索引,next key lock则不会降级
宕机造成的影响
当取消自动提交我们两个事务并发,然后事务2在之前是拿到锁的,然后事务2挂掉了,此时事务1begin,然后进行update,发现竟然踏马阻塞了
——>得到结论:当事务拿到锁资源没有提交后,这个锁资源会一直占用,然后宕机后,一直占着
SQL|MVCC在重复读和读已提交场景以及幻读的解决
文章图片

今天还遇到一个情况,我两个并发事务全部阻塞了,经过排查是因为之前的事务因为宕机没有释放锁,后面show了一下,然后全部kill掉了
show processlist

(40条消息) MySQL锁等待问题(ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction)_sunon_的博客-CSDN博客


    推荐阅读