| test100 | CREATE TABLE `test100` ( `sn` int(11) NOT NULL AUTO_INCREMENT COMMENT '自增编号', `phoneNo` int(11) DEFAULT NULL, `channelType` int(11) DEFAULT NULL COMMENT '通道识别', `status` tinyint(4) NOT NULL COMMENT '短信转态,1.发送成功,2.发送失败,3.发送异常', PRIMARY KEY (`sn`), UNIQUE KEY `test100_idx1` (`phoneNo`) Session 1: mysql> select * from test100 where phoneNo between 10 and 20 for update; +----+---------+-------------+--------+ | sn | phoneNo | channelType | status | +----+---------+-------------+--------+ | 10 | 10 | 2 | 1 | | 11 | 11 | 2 | 1 | | 16 | 16 | 2 | 1 | | 17 | 17 | 2 | 1 | | 18 | 18 | 2 | 1 | | 19 | 19 | 2 | 1 | | 20 | 20 | 2 | 1 | +----+---------+-------------+--------+ 7 rows in set (0.00 sec) mysql> rollback; Query OK, 0 rows affected (0.00 sec) mysql> start transaction; Query OK, 0 rows affected (0.00 sec) mysql> select * from test100 where phoneNo=16 for update; +----+---------+-------------+--------+ | sn | phoneNo | channelType | status | +----+---------+-------------+--------+ | 16 | 16 | 2 | 1 | +----+---------+-------------+--------+ 1 row in set (0.00 sec) Session 2: mysql> insert into zjzc.test100(PhoneNo,channelType,status) values(15,1,1); Query OK, 1 row affected (0.01 sec) mysql> insert into zjzc.test100(PhoneNo,channelType,status) values(14,1,1); Query OK, 1 row affected (0.01 sec) mysql> insert into zjzc.test100(PhoneNo,channelType,status) values(17,1,1); ERROR 1062 (23000): Duplicate entry '17' for key 'test100_idx1' mysql> 此时RR模式下唯一索引 可以插入 /**************************************************************** mysql> select * from test100 where phoneNo<20; +----+---------+-------------+--------+ | sn | phoneNo | channelType | status | +----+---------+-------------+--------+ | 1 | 1 | 2 | 1 | | 2 | 2 | 2 | 1 | | 3 | 3 | 2 | 1 | | 4 | 4 | 2 | 1 | | 5 | 5 | 2 | 1 | | 6 | 6 | 2 | 1 | | 7 | 7 | 2 | 1 | | 8 | 8 | 2 | 1 | | 9 | 9 | 2 | 1 | | 10 | 10 | 2 | 1 | | 11 | 11 | 2 | 1 | | 16 | 16 | 2 | 1 | | 17 | 17 | 2 | 1 | | 18 | 18 | 2 | 1 | | 19 | 19 | 2 | 1 | +----+---------+-------------+--------+ 15 rows in set (0.00 sec) 测试非唯一索引情况下: | test100 | CREATE TABLE `test100` ( `sn` int(11) NOT NULL AUTO_INCREMENT COMMENT '自增编号', `phoneNo` int(11) DEFAULT NULL, `channelType` int(11) DEFAULT NULL COMMENT '通道识别', `status` tinyint(4) NOT NULL COMMENT '短信转态,1.发送成功,2.发送失败,3.发送异常', PRIMARY KEY (`sn`), KEY `test100_idx1` (`phoneNo`) ) ENGINE=InnoDB AUTO_INCREMENT=5023 DEFAULT CHARSET=utf8 COMMENT='短信发送成功记录表' Session 1: mysql> start transaction; Query OK, 0 rows affected (0.00 sec) mysql> select * from test100 where phoneNo=16 for update; +----+---------+-------------+--------+ | sn | phoneNo | channelType | status | +----+---------+-------------+--------+ | 16 | 16 | 2 | 1 | +----+---------+-------------+--------+ 1 row in set (0.00 sec) Session 2: mysql> insert into zjzc.test100(PhoneNo,channelType,status) values(14,1,1); --hang mysql> insert into zjzc.test100(PhoneNo,channelType,status) values(13,1,1); -hang mysql> insert into zjzc.test100(PhoneNo,channelType,status) values(15,1,1); -hang mysql> insert into zjzc.test100(PhoneNo,channelType,status) values(16,1,1); -hang mysql> insert into zjzc.test100(PhoneNo,channelType,status) values(17,1,1); Query OK, 1 row affected (0.01 sec) 结论: For a unique index with a unique search condition, InnoDB locks only the index record found, not the gap before it. 对于唯一索引使用唯一条件搜索, InnoDB 只锁定找到的index record,不是它之前的区间 For other search conditions, InnoDB locks the index range scanned, using gap locks or next-key locks to block insertions by other sessions into the gaps covered by the range. 对于其他搜索条件, InnoDB 扫描的索引范围,使用gap lock or next-key locks 来堵塞其他会话插入这个区间 区间锁: 一个区间锁 是一个锁在index记录之间的区间,或者一个锁在第一个或者最后一个index记录的区间 比如,SELECT c1 FOR UPDATE FROM t WHERE c1 BETWEEN 10 and 20; 组织其他事务插入值为15到t.c1列,不管是否这里已经有这些的值存储, 因为区间锁是在所有存在的值在这个范围被锁定 一个区间锁扩约一个单独的索引值,多个索引值,甚至是空的 区间锁是权衡并发和性能的一部分, 用于一些事务隔离而不是其他 Gap 锁定不能用于语句 ,锁定记录使用一个unique index来搜索用于一个唯一的记录 (这个不能包含例子 搜索条件只包含多列唯一索引的一些列,在那种情况下,gap locking 也存在) 比如, 如果Id列有一个唯一索引,下面语句只用一个index-record锁用于记录id值为100 它不管是否其他灰灰插入记录到前面的区间 SELECT * FROM child WHERE id = 100; 如果id没有被索引或者有一个非唯一索引,语句会锁前面的区间 在InnoDB中Gap locks 是"纯粹抑制的", 这意味着它们只能停止其他事务防止插入到这个区间。 它们不阻止不同的事务来利用区间锁在相同的区间 区间锁可以被显示禁用, 这个发生如果你改变的事务隔离为 READ COMMITTED 或者启用了innodb_locks_unsafe_for_binlog 在这群情况下, 区间锁是被禁用的用于搜索和索引扫描