分析一条语句的加锁行为,我们需要知道:
- 当前隔离级别是什么?
- 语句是快照读还是当前读?
- 是不是走的索引?
- 索引是不是主键?
- 索引唯一吗?
快照读默认不加锁,走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锁,并且要在锁住所有间隙。
-
情形4-id不是索引
因为id不是索引,所以该语句需要进行全表扫描,这种情况下会对主键索引的所有记录和间隙都加锁。这种情况并发度就很低了,而且如果记录很多锁的开销还非常大。
似乎进行扫描时只要对满足条件的加锁即可,但实际上innodb会先对所有的记录加锁,然后在mysql server层会进行过滤,对不满足条件的记录释放锁(但这违背了2PL原则)。
RC隔离级别下:
基本和RR一样,不过不考虑幻读问题,不需要加间隙锁。
- id是主键,同RR
- id是唯一索引,同RR,不需要加间隙锁
- id是非唯一索引,同RR,不需要加间隙锁
- id不是索引,同RR,不需要加间隙锁
串行化隔离级别:
在串行化下,上述的当前读语句加锁行为和RR级别一样。
不同的是串行化级别下所有读都是当前读,不走快照读,因此原本的快照读语句会加读锁。MVCC并发控制降级为Lock-Based CC。