目录

加锁的规则

前提:可重读读的事务隔离下

原则 1 : 加锁的基本单位是Next key Lock ,即 :间隙锁 + 行锁

原则 2 : 访问过的对象都会进行加锁

优化 1 : 索引上的等值查询,给唯一索引加锁时,会退化为行锁

优化 2 : 索引上的等值查询,向右遍历时且最后一个值不满足等值条件的时候,退化为间隙锁

一个Bug :唯一索引上的范围查询会访问到不满足条件的第一个值为止

锁是加在索引上面的

大于值,就从该值之后去寻找,等于该值,就从该值前一个值寻找

“间隙”,其实根本就是由“这个间隙右边的那个记录”定义的,比如从右往左扫描,扫到10,加的锁范围就是(5,10]

通过explain的结果,就能够脑补出一个SQL语句的执行流程

主键索引范围锁

非唯一索引范围锁

唯一索引范围锁bug

非唯一索引上存在”等值”的例子

limit语句加锁

一个死锁的例子

不等号条件的等值查询

begin;
select * from t where id > 9 and id < 12 order by id desc for update;
-- 加锁范围是主键索引上的 (0,5]、(5,10]和(10, 15)
-- Order by id desc 是从大到小进行加锁的

这里面也是有等值查询的,对于id < 12 ,引擎内部,找的是id = 12 这个值,只是最终没找到,找到了(10, 15)的间隙,之后就进行向左遍历,遍历过程中,不是等值查询,会扫描到id = 5,会加一个(0,5],因为加锁基本单位为Next Key

锁是“在执行过程中一个一个加的”,而不是一次性加上去的

锁等待

Session A Session B
begin; select * from t where id > 10 and id <= 15 for update xx
xx delete from t where id=10(Query OK)insert into t values(10, 10, 10)blocked

delete删除了锁的间隙就变大了,原来是(5,10],(10,15] 删除完后就变为(5,15]

id > 10 于是从10以后开始找

update

Session A Session B
begin; select c from t where c > 5 lock in share mode xx
xx update t set c = 1 where c = 5 (Query OK) update t set c = 5 where c = 1(blocked)

加锁:(5, 10],(10,15]..(25,+]

要把c=5改成c=1,你可以理解为两步:

  1. 插入(c=1, id=5)这个记录
  2. 删除(c=5, id=5)这个记录