MySQL隔离级别面试高频

124 阅读6分钟

1. MySQL的隔离级别有哪几种?

image.png

2. Mysql隔离级别默认是哪个?为啥是RR?

  • MySQL隔离默认级别是RR。

  • MySQL主从复制的过程中,其实就是把binlog复制给从节点,从节点从bin log中再将数据恢复到自己的库中。 其中bin log有3种格式,分别是statement、row以及mixed。MySQL早期只有statement这种bin log格式,这种格式下,bin log记录的其实就是SQL语句原文。

我们来举个例子: 有1张表t1,里面有a,b两个字段,都是int类型。现在有两个会话,会话1执行 delete from t1 where b < 100,会话2执行insert into t1 values(2,80)。其中会话1先于会话2执行事务,会话1的删除操作也早于会话2的插入操作,但是会话2事务提交早于会话1.

以上两条SQL语句,由于会话2事务提交的早,因此在bin log中会先记录 insert 语句,后记录delete语句。 那么从节点接收到之后,按顺序执行两条SQL后,从数据库中根本就不存在(2,80)的数据。这就导致主从数据不一致的问题了。

为了避免这种情况的出现,MySQL将隔离级别改成了 RR 可重复读。这种隔离级别下,会在更新数据的时候添加一个行级锁。

我们看看这RR这种隔离级别下是如何执行上面的例子的,当会话1开始执行事务后,会增加一个行级锁 ,这个时候就会导致会话2的事务卡主,需要等待事务1提交或者回滚后才能执行。这样也就完美的解决主从不一致的问题了。

这就是为啥默认是RR隔离级别。


3. RR的缺点是什么?RR相比RC多了什么?为啥很多大公司要把RR改成RC?

  • 首先,提升并发。RC在加锁的过程中,是不需要添加间隙锁Gap lock和 Next-key lock的,它只需要对修改的记录添加行级锁就行了。而RR为了避免幻读,不仅支持行级锁,还要支持间隙锁和next-key lock,那么这就使得RR的并不度不如RC。

  • 再一个就是:减少死锁。RR支持的锁较多,使得锁的粒度比较大,那么死锁的概率也就大一些。


4. Mysql的行级锁到底锁的是什么东西?

数据库的行级锁根据锁的粒度不同,分为3种:

  1. Record Lock表示记录锁,锁的是索引记录;
  2. Gap Lock是间隙锁,锁的是索引记录之间的间隙;
  3. Next-Key Lock是上面两种锁的组合,同时记录锁索引记录和间隙。
  • 首先解释第1种锁 Record Lock,例如 select a from stu where age = 20 for UPDATE; 会对age = 20 的这条记录加锁,这是为了防止其他事务插入、更新、删除操作对其产生更改。
  • 其次 Gap Lock,指的是在索引记录之间的间隙上的锁。 Gap指的是innoDB的索引数据结构中可以插入新值的位置。例如 select a from stu where age < 20 for UPDATE; 在这条SQL中,我们选择的是 age < 20 的全部值进行更新,那么间隙锁此时就会阻止插入 age < 20 的新数据。 (间隙锁会影响数据库的并发性,而且只会在RR这种隔离级别下有效)
在RR这种隔离级别下:
* 对于具有唯一搜索条件的唯一索引,InnoDB只会锁定找到的索引记录,而不会锁定间隙;
* 对于其他搜索条件,InnoDB锁定的是索引范围,会使用Gap Lock或Next-Key Lock来阻塞插入范围覆盖的间隙。
也就是说,除了有唯一索引会使用Record Lock记录锁,其余都视为范围索引,使用间隙锁Gap Lock或Next-Key Lock。
  • 最后,再说一下Next-Key Lock,指的是索引上的记录锁和索引之前范围的间隙锁的组合。
例如书架上有编号为5,10,15,20的这几本书,我们此时要查找编号大于5且小于等于15的数,
`select bookName from book where bh > 5 and bh <= 15;` 此时InnoDB会做两件事:
* 锁住查找到的书,即编号10和15;
* 锁住这些书前面的间隙,即编号5到10、10到15前的间隙.
这样如果别人要在5到10之间插入编号7的书就会被阻止,这样也就不会在你查询中突然"看到"一本新书,也就是幻读.

Next-Key Lock和 Gap Lock一样,只会在InnoDB的RR隔离级别下生效.


5. RR解决了幻读吗?完全解决了吗?

解决了,但没有完全解决。

InnoDB中,RR隔离级别通过间隙锁+MVCC机制解决了大部分的幻读,想要彻底解决,还必须借助Serializable序列化的隔离级别。

  • RR中,通过间隙锁将记录之间的间隙锁住,避免了操作之间的数据插入,解决了部分当前读的幻读问题。
  • RR中,通过MVCC机制,解决了快照读的幻读问题,RR中只有第一次会进行数据查询,其余都是直接读取快照,不会产生幻读。

但是,如果两个事务,事务1先进行快照读,事务2再进行了更新并提交,再在事务1中更新的这条记录是可以操作成功的,这就产生了幻读

还有就是,事务1先进行幻读,事务2再进行更新并提交,在事务1中进行了当前读之后,再进行快照读也会发生幻读。


6. MySQL的加锁原则

总结下来,包含了两个原则、两个优化和1个BUG:

原则:

  1. 加锁的默认基本单位是Next-Key Lock,是一个前开后闭区间;
  2. 查找过程中访问到的对象才会加锁。

优化:

  1. 索引上的等值查询,如果是给唯一索引加锁,Next-Key Lock会退化成行锁Record Lock;
  2. 索引上的等值查询,向右遍历时且最后一个值不满足等值条件的时候,会退化成间隙锁Gap Lock。

一个BUG:

唯一索引上的范围查询会访问到不满足条件的第一个值为止。