0%

由mysql的默认隔离级别引出的几个问题

  • 讲讲mysql有几个隔离级别?
  • mysql的默认隔离级别是哪个?
  • 你们项目中选了哪个隔离级别,为什么?

这上面三个问题是面美团的时候被问到的。。前两个还好。。第三个让我有点摸不着头脑。。查了些资料之后就记录一下这个问题吧

Q1: MySQL有几个隔离级别

送分题… 读未提交,读提交,可重复读,串行化

Q2: Mysql的默认隔离级别是哪个?

送分题… mysql默认是可重复读,但oracle等其他的几个默认好像都是读提交…

而mysql默认是可重复也是有历史原因的,mysql的主从一致性是会通过binlog来做,而早期的mysql的binlog仅支持statement模式,因为保存的是执行的命令,在RC级别下可能会导致主从不一致,而这一问题在RR级别下就能够得到解决,所以就一直默认的使用RR级别

参考链接

Q3: 你们项目中选了哪个隔离级别,为什么?

= = 作为一个零项目的蒟蒻,虽然答不上来自己的项目里使用了哪个隔离级别,但可以说一下一般会使用哪个隔离级别。。

如果没有RR(可重复读)的需求的话,能使用RC还是使用RC(读提交)。。

有以下几个原因:

原因一:在RR隔离级别下,存在间隙锁,导致出现死锁的几率比RC大的多

这里说一个间隙锁导致死锁的例子:

  1. 事务A使用间隙锁锁住了Id为(1,5)的索引, 然后插入一条id=8的记录
  2. 然后在尝试插入一条id=8的记录前发生了调度,轮到事务B去执行
  3. 事务B锁住了id为(6,10)的索引,然后尝试插入一条id=3的记录,然因为被事务A锁住了,所以等待
  4. 事务A又获得了执行权,开始执行插入id=8的记录,但因为id属于(6,10)的这个区间被事务B锁住了,所以等待事务B
  5. 事务B等事务A,事务A等事务B,死锁发生了..

而在RC隔离级别下,不存在间隙锁,其他事务是可以插入数据!

ps:在RC隔离级别下并不是不会出现死锁,只是出现几率比RR低而已!

原因二:在RR隔离级别下,条件列未命中索引会锁表!而在RC隔离级别下,只锁行

在RC隔离级别下,如果走聚簇索引进行全表扫描的时候,实际操作中,MySQL进行了改进,在进行过滤条件时,发现不满足条件后,会调用 unlock_row 方法,把不满足条件的记录放锁 , 即锁的粒度是行锁

但是!!在RR隔离级别下,走聚簇索引,进行全部扫描,最后会将整个表锁上,锁的粒度是表级锁!!

参考链接

*原因三:在RC隔离级别下,半一致性读(semi-consistent)特性增加了update操作的并发性

在RC隔离级别或者innodb_locks_unsafe_for_binlog被设置为true,并发时,如果update的记录发生锁等待,那么返回该记录的prev 版本(在返回前会将锁等待的这个lock从trx中删除掉),到mysql层进行where判断,是否满足条件。如果满足where条件,那么再次进入innodb层,真正加锁或者发生锁等待。

这样做的好处是:减少同一行记录的锁冲突及锁等待;无并发冲突时,直接读取最新版本加锁,有冲突时,不加锁,读取prev版本不需要锁等待。

缺点:非冲突串行话策略,对于binlog来说是不安全的。只能发生在RC隔离级别和innodb_lock_unsafe_for_binlog下。

参考链接


其实Q3感觉说前两个原因就行了,第三个原因了解下吧.. 因为并不是在RC级别下特有的,设置innodb_locks_unsafe_for_binlog=true好像也可..