带你了解record lock、gap lock、next-key lock

2,514 阅读4分钟

1.前言

不管java编程语言还是mysql数据库都有的概念,存在的目的就是为了保护共享资源,避免并发情况都去操作共享资源,从而出现数据不一致的情况。InnoDB Locking一文可以你可以了解到Record LocksGap LocksNext-Key Locks相关介绍,本文主要介绍sql语句加锁相关内容。

2.锁介绍

  • Record Locks:行锁,对一行记录进行加锁
  • Gap Locks:间隙锁,对范围记录进行加锁
  • Next-Key Locks:由Record LocksGap Locks组成

3. 示例

3.1 创建表

create table t(
    id int(10) not null primary key,
    c int(10) not null,
    d int(10) not null,
index(c));

3.2 插入数据

insert into t values(0, 0, 0);
insert into t values(5, 5, 5);
insert into t values(10, 10, 10);
insert into t values(15, 15, 15);
insert into t values(20, 20, 20);
insert into t values(25, 25, 25);
insert into t values(30, 30, 30);

如上一共插入6条数据,会产生7个区间范围:(-∞,0)、(0,5)、(5,10)、(10,15)、(15,20)、(20,25)、(25,+supremum),对应next-key lock:(-∞,0]、(0,5]、(5,10]、(10,15]、(15,20]、(20,25]、(25,+supremum],由于next-key lock包含行锁,因此会形成前开后闭区间范围

在开始演示前,先带你了解下具体加锁规则

3.3 加锁规则

  • 加锁基本单位next-key lock,next-key lock = 间隙锁 + 行锁,前开后闭
  • 查询过程中访问到的对象都要加锁
  • 索引等值查询,给唯一索引加锁时,next-key lock会退化为行锁
  • 索引等值查询,向右遍历时且最后一个值不满足查询条件,next-key lock会退化为间隙锁
  • 索引上的范围查询会访问到不满足条件的第一个值为止

3.4 唯一索引等值查询加锁

3.4.1 记录存在的等值查询

session1session2
begin;
select * from t where id = 5 for update;
begin;
insert into t values(8, 8, 8);pass
update t set c = c + 1 where id = 5;blocked
rollback;
rollback;

第一条规则,加锁加next-key lock(0, 5],第三条规则,给唯一索引加锁,会退化为行锁,最终只对id = 5这一行记录进行加锁

3.4.2 记录不存在的等值查询

session1session2
begin;
select * from t where id = 7 for update;
begin;
insert into t values(8, 8, 8);blocked
update t set c = c + 1 where id = 10;pass
rollback;
rollback;

第一条规则,加锁加next-key lock(5, 10],第4条规则10不满足查询条件(id = 7),退化为间隙锁(5,10)

3.5 非唯一索引等值查询加锁

3.4.1 记录存在的等值查询

session1session2
begin;
select * from t where c = 5 for update;
begin;
insert into t values(4, 4, 4);blocked
insert into t values(8, 8, 8);blocked
update t set d = d + 1 where c = 5;blocked
update t set d = d + 1 where c = 10;pass
rollback;
rollback;

第一条规则,加锁加next-key lock(0, 5],由于c索引是非唯一索引,会继续往后查找,找到10这条记录,不满足,返回,第二条规则查找过程中访问到的对象会被加锁,因此加锁范围包括(5,10],根据第四条规则,加锁范围为(5,10),最终加锁范围(0,5]、(5,10)

3.4.2 记录不存在的等值查询

session1session2
begin;
select * from t where c = 7 for update;
begin;
insert into t values(8, 8, 8);blocked
update t set c = c + 1 where c = 10;pass
rollback;
rollback;

第一条规则,加锁加next-key lock(5, 10],第4条规则10不满足查询条件(c = 7),退化为间隙锁(5,10)

3.6 唯一索引范围查询加锁

session1session2
begin;
select * from t where id >= 10 and id < 15 for update;
begin;
insert into t values(12, 12, 12);blocked
update t set d = d + 1 where id = 10;blocked
rollback;
rollback;

第一条规则,加锁加next-key lock(5,10],第三条规则,退化为行锁,只对id = 10这条记录加锁,根据第五条规则,(10,15]区间范围也会被加锁

3.7 非唯一索引范围查询加锁

session1session2
begin;
select * from t where c >= 5 and c < 10 for update;
begin;
insert into t values(2, 2, 2);blocked
insert into t values(7, 7, 7);blocked
update t set d = d + 1 where c = 10;blocked
rollback;
rollback;

第一条规则,加锁加next-key lock(0,5],非唯一索引会继续往下查找,找到10这条记录发现不满足,返回,第二条规则查找过程中访问到的对象会被加锁,因此加锁范围包括(5,10],最终加锁范围(0,5]、(5,10]

4.参考文献

更多讲解可以参考