1.前言
不管java
编程语言还是mysql
数据库都有锁
的概念,锁
存在的目的就是为了保护共享资源,避免并发情况都去操作共享资源,从而出现数据不一致的情况。InnoDB Locking一文可以你可以了解到Record Locks
、Gap Locks
、Next-Key Locks
相关介绍,本文主要介绍sql
语句加锁相关内容。
2.锁介绍
Record Locks
:行锁,对一行记录进行加锁Gap Locks
:间隙锁,对范围记录进行加锁Next-Key Locks
:由Record Locks
和Gap 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 记录存在的等值查询
session1 | session2 |
---|---|
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 记录不存在的等值查询
session1 | session2 |
---|---|
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 记录存在的等值查询
session1 | session2 |
---|---|
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 记录不存在的等值查询
session1 | session2 |
---|---|
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 唯一索引范围查询加锁
session1 | session2 |
---|---|
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 非唯一索引范围查询加锁
session1 | session2 |
---|---|
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.参考文献
更多讲解可以参考