MySQL加锁处理分析

本篇文章以MySQL的InnoDB存储引擎为前提进行分析。不同的存储引擎,锁机制不一样。

首先我们从一道面试题入手来看看MySQL如何进行加锁处理。

select * from student where id = 1;
update from student set name = ‘a’ where id = 1;
student字段有三个:id,name,core
这两条语句分别加什么锁?

当拿到这样一道面试题的时候,有几个问题一定要向面试官问清楚。

  1. id是不是索引?如果是,是聚集索引还是非聚集索引?
  2. id是不是主键?关于主键和索引的区别请看另一篇博客
  3. 当前数据库的隔离级别?一般会说明是InnoDB存储引擎,那就表明隔离级别是RR(Repeatable Read)

这些前提了解清楚后,让我们来看看这道题的答案。

select

select * from table1 where id = 1;

不管id是不是主键,是聚集索引还是非聚集索引,只要在RR隔离级别下,select操作都是不加锁的。

update

update from student set name = ‘a’ where id = 1;

下面结合以上的一些前提条件来看看update下的加锁处理

  • 情况1:id是主键
    会给id=10的记录行加X锁。

  • 情况2:id是唯一索引,name是主键
    id是聚集索引,那update时会走索引进行where条件的过滤,在找到id=1的记录行后,会给id=1的记录行加上行锁X锁。同时因为name是主键,在找到id=1的记录id=1,name=’SMonkeyKing’,score=100后,会对主键name=’SMonkeyKing’的聚集索引加上X锁。思考一下,这里为什么要所索引项加锁?
    因为如果我们没有对主键索引上的记录加锁,那么当并发执行update时,如update from student set name=‘b’ where id = 1;时,不会感知到上一个update语句。这就违背了同一记录上的更新/删除操作要串行执行的约束。

  • 情况3:id是非唯一索引,name是主键
    如果id是非唯一索引,那通过where条件过滤后可能存在多条记录,或者是没有记录。这里的加锁处理和情况2一样,首先对满足条件的记录行加锁,然后对相应的主键索引项加锁。

  • 情况4:id没有索引,name是主键
    id上没有索引的情况下,数据库会通过主键进行查询,即走聚集索引。聚集索引上所有的记录都会被加上X锁。为什么不是只对满足条件的记录加锁?
    这是由于 MySQL 的实现决定的。如果一个条件无法通过索引快速过滤,那么存储引擎层面就会将所有记录加锁后返回,然后由 MySQL Server 层进行过滤。 因此也就把所有的记录,都锁上了。
    注: 在实际的实现中, MySQL 有一些改进,在 MySQL Server 过滤条件,发现不满足后,会调用 unlock_row 方法,把不满足条件的记录放锁 (违背了 2PL 的约束)。这样做,保证了最后只会持有满足条件记录上的锁,但是每条记录的加锁操作还是不能省略的。

猜你喜欢

转载自blog.csdn.net/SMonkeyKing/article/details/82350612