赞
踩
目录
跟间隙锁存在冲突关系的,是“往这个间隙中插入一个记录”这个操作。间隙锁之间都不存在冲突关系。
间隙锁和行锁合称next-key lock,每个next-key lock是前开后闭区间。也就是说,我们的表t初始化以后,如果用select * from t for update要把整个表所有记录锁起来,就形成了7个next-key lock,分别是 (-∞,0]、(0,5]、(5,10]、(10,15]、(15,20]、(20, 25]、(25, +suprenum]。
间隙锁记为开区间,把next-key lock记为前开后闭区间。
帮我们解决了幻读的问题,但同时也带来了一些“困扰”。
锁住范围更大,更加可能造成死锁,影响并发度。
一些公司解决方案---》读提交隔离级别加binlog_format=row的组合。
原则1:加锁的基本单位是next-key lock。next-key lock是前开后闭区间。
原则2:查找过程中访问到的对象才会加锁。
优化1:索引上的等值查询,给唯一索引加锁的时候,next-key lock退化为行锁。
优化2:索引上的等值查询,向右遍历时且最后一个值不满足等值条件的时候,next-key lock退化为间隙锁。
一个bug:唯一索引上的范围查询会访问到不满足条件的第一个值为止。
update t set d=d+1 where c=7;
select id from t c=7 lock in share mode;
select * from t where id>=10 and id<11 for update;
加锁结果:行锁id=10和next-key lock(10,15]
select * from t where c>=10 and c<11 for update;
加锁结果:索引c上的(5,10] 和(10,15] 这两个next-key lock
select * from t where id>10 and id<=15 for update;
加锁结果: (10,15]这个next-key lock,(15,20]这个next-key lock也会被锁上。
增加:insert into t values(30,10,30);
加锁结果:(c=5,id=5)到(c=10,id=10)这个next-key lock;(c=10,id=10) 到 (c=15,id=15)的间隙锁。
案例七里的delete语句明确加了limit 2的限制,因此在遍历到(c=10, id=30)这一行之后,满足条件的语句已经有两条,循环就结束了。
加锁结果:c=5,id=5)到(c=10,id=30)这个前开后闭区间。
分析
session A 启动事务后执行查询语句加lock in share mode,在索引c上加了next-key lock(5,10] 和间隙锁(10,15);
session B 的update语句也要在索引c上加next-key lock(5,10] ,进入锁等待;
然后session A要再插入(8,8,8)这一行,被session B的间隙锁锁住。由于出现了死锁,InnoDB让session B回滚
结论:在分析加锁规则的时候可以用next-key lock来分析。但是要知道,具体执行的时候,是要分成间隙锁和行锁两段来执行的。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。