参考资料:MySQL的锁(完整篇)
MySQL数据库包含各种锁,为方便了解,我们按照分类逐个简单介绍。
按照是否允许同时访问
对于某行记录,会存在多个事务同时访问的情况,我们可以分为共享锁和独占锁。
共享锁
英文名:Shared Locks,简称:S锁。顾名思义,允许多个事务同时共享数据。
加锁方式:
select * from t where id = 1 lock in share mode;
当事务A访问记录1时,先给记录1加个共享锁;接着,事务B也打算访问记录1,此时也加个共享锁,允许访问。
独占锁
英文名:Exclusive Locks,简称:X锁。顾名思义,仅允许一个事务访问记录。
加锁方式:
select * from t where id = 1 for update;
当事务A访问记录1时,先给记录1加个独占锁;接着,事务B打算访问记录1,无论事务B想加S锁还是X锁,都要阻塞等待事务A提交后才可以访问记录1。
各种情况加锁
- 假设记录1没有加锁,事务A过来加个
S锁。接着,事务B姗姗来迟,如果它加S锁,没问题,可以访问;如果它加X锁,那得等事务A提交完才可以访问 - 假设记录1没有加锁,事务A过来加个
X锁。接着,事务B姗姗来迟,无论它加S锁还是X锁,都得等事务A提交才可以访问
按照锁的颗粒度
按照锁的颗粒度,可以分为表锁和行锁。除此以外,为了保证事务的隔离级别,还诞生了意向锁、间隙锁等等。
表锁
表锁,Table Locks,顾名思义,锁定整个表里面的所有记录,会分为表共享锁和表独占锁。
加锁方式:
# 共享锁
LOCK TABLES t READ;
# 独占锁
LOCK TABLES t WRITE;
兼容性:
- 如果一个事务给表加了共享锁,其他事务可以同样加共享锁,但是不能加独占锁
- 如果一个事务给表加了独占锁,其他事务不可以加任何锁
行锁
行锁,Record Locks,顾名思义,锁定某行记录。同样,也会分S锁和X锁,加锁方式就不再赘述。
意向锁
试想一个情景:事务A过来给表加个独占锁,那么它得确认表中所有记录都没有加锁,这样它才可以加锁成功。怎么确认呢,逐行遍历吗??当然不是啦,为了快速判断这个表的记录有没有被锁定,诞生了意向锁的概念。
如果事务B需要对记录1加独占锁,那么先要获取这个表的意向独占锁;如果需要对记录1加共享锁,那就先获取这个表的意向共享锁。因此,当事务A需要加表锁时,根据这个表的意向锁就可以判断行记录的锁状态。
意向锁,Intension Lock,分为IS锁和IX锁。
以上,把基本的锁介绍完毕,但是为了解决幻读的问题,InnoDB还有间隙锁、Next-Key锁。接下来,也把它们介绍完
间隙锁
MySQL在可重复读的隔离级别下,是可以解决幻读问题的。解决方法有两个,一个是MVCC方案解决,一个是采用加锁方式(至于使用哪种方式,要具体分析,暂时没了解)。由于幻读是指在查询条件相同时,重复查询,会读取到之前没有的数据。为此,官方提出了间隙锁的概念。
间隙锁,Gap Locks。
来个栗子:下图所示,给number值为8的行记录加了间隙锁,意味着不允许其他事务在这条记录前面的间隙插入新纪录,也就是(3,8)区间不能新增记录。
间隙锁的提出,仅仅是为了防止插入幻影记录而提出的。
Next-Key Locks
Next-Key Locks就是行锁+间隙锁,既锁定当前记录,又禁止在当前记录前的间隙中插入新纪录。
意向插入锁
事务在插入记录时,先判断插入位置是不是被其他事务加了gap锁,如果有的话,需要在内存结构中生成一个锁结构,表明有个事务想在折这个间隙插入记录。这种锁就是Insert Intension Locks,插入意向锁。