Record Lock老是会锁住索引记录,若是InnoDB存储引擎表在创建的时候没有设置任何一个索引,那么这时InnoDB存储引擎会使用隐式的主键来进行锁定。算法
设计目的:是为了解决Phantom Problem(幻象/幻读),利用这种锁技术,锁定的不是单个值,而是一个范围。markdown
Next-Key Lock是结合了Gap Lock和Record Lock的一种锁定算法,在此种算法下,InnoDB对于行的查询都是采用这种锁定算法。并发
例如:优化
有十、十一、1三、20这四个值,那么索引可能被Next-Key Locking的区间为:spa
一、(-∞,10]设计
二、(10,11]code
三、(11,13]orm
四、(13,20]索引
五、(20,+∞)事务
除了Next-Key Locking,还有Previous-Key Locking,如上面的例子,可锁定的区间为:
一、(-∞,10)
二、 [10,11)
三、 [11,13)
四、 [13,20)
五、 [20,+∞)
然而,当查询的索引含有惟一属性时,InnoDB存储引擎对Next-Key Lock进行优化,将其降级为Record Lock,即仅锁住索引自己,而不是范围。如表中有1,2,5的id数据:
会话A首先对a=5进行X锁。而因为a是主键且惟一,所以锁定的仅是5这个值,而不是(2,5)的范围,这样在B中插入值4不会阻塞,能够当即插入并返回。即锁定由Next-Key Lock算法降级为Record Lock,从而提升了并发性。
Next-Key Lock降级为Record Lock仅在查询的列是惟一索引的状况下。
如果辅助索引,则状况会彻底不一样如:
CREATE TABLE z(a INT,b INT,PRIMARY KEY(a),KEY(b))
INSERT INTO z SELECT 1,1;
INSERT INTO z SELECT 3,1;
INSERT INTO z SELECT 5,3;
INSERT INTO z SELECT 7,6;
INSERT INTO z SELECT 10,8;
表z的b列是辅助索引,若在会话A中执行下面的SQL:
SELECT * FROM z WHERE b=3 FOR UPDATE;
这是Sql语句经过索引列b进行查询,所以其使用传统的Next-Key Locking加锁,而且因为两个索引,其须要分别进行锁定。对于汇集索引,其仅对a等于5的索引加上record Lock。对于辅助索引,其加上的是Next-Key Lock,锁定的范围是(1,3),须要注意的是,InnoDB存储引擎还会对辅助索引下一个键值加上gap lock,即还有一个辅助索引的范围为(1,6)的锁,所以,在B会话中运行下面的Sql语句,都会被阻塞:
SELECT * FORM z WHERE a=5 LOCK IN SHARE MODE;
INSERT INTO z SELECT 4,2;
INSERT INTO z SELECT 6,5;
而执行下面的语句,不会阻塞:
INSERT INTO z SELECT 8,6;
INSERT INTO z SELECT 2,0;
INSERT INTO z SELECT 6,7;
在默认的事务隔离级别下,即REPEATABLE READ下,InnoDB存储引擎采用Next-Key Locking机制来避免Phantom Problem(幻象问题)