【innoDB】加锁案例分析

分析一条语句的加锁行为,我们需要知道:

  • 当前隔离级别是什么?
  • 语句是快照读还是当前读?
  • 是不是走的索引?
  • 索引是不是主键?
  • 索引唯一吗?

快照读默认不加锁,走mvcc,下面分析一下当前读的常见场景,sql语句是:update t1 set name='xx' where id=10;

RR隔离级别级别:

可重复读通常需要加间隙锁保证不出现幻读。

  • 情形1- id是主键索引

    这种情况下只会在id=10的主键索引上加X锁

  • 情形2-id是非主键唯一索引

    唯一索引id=10上先被加X锁;还要在该记录的主键索引上加X锁;

    如果不存在id=10的记录,则要在id索引上加间隙锁,锁住id=10其前一条记录到其后一条记录这整个区间。

  • 情形3- id是非唯一索引

    所有索引到的记录都加上X锁,并在其主键索引上也加上X锁,并且要在锁住所有间隙。

    image-20211212203545964
  • 情形4-id不是索引

    因为id不是索引,所以该语句需要进行全表扫描,这种情况下会对主键索引的所有记录和间隙都加锁。这种情况并发度就很低了,而且如果记录很多锁的开销还非常大。

    似乎进行扫描时只要对满足条件的加锁即可,但实际上innodb会先对所有的记录加锁,然后在mysql server层会进行过滤,对不满足条件的记录释放锁(但这违背了2PL原则)。

RC隔离级别下:

基本和RR一样,不过不考虑幻读问题,不需要加间隙锁。

  • id是主键,同RR
  • id是唯一索引,同RR,不需要加间隙锁
  • id是非唯一索引,同RR,不需要加间隙锁
  • id不是索引,同RR,不需要加间隙锁

串行化隔离级别:

在串行化下,上述的当前读语句加锁行为和RR级别一样。

不同的是串行化级别下所有读都是当前读,不走快照读,因此原本的快照读语句会加读锁。MVCC并发控制降级为Lock-Based CC。

原文地址:https://www.cnblogs.com/cpcpp/p/15684239.html