Gap Locks 区间锁

Gap Locks 区间锁

1.
区间锁不能用于语句锁定记录使用一个唯一索引来搜索一个唯一的记录

2.READ COMMITTED 没有区间锁



区间锁是一个锁在一个在index记录间的区间,或者一个lock 在gap 在第一个前或者最后一个index recoed 之后,


比如,SELECT c1 FOR UPDATE FROM t WHERE c1 BETWEEN 10 and 20; 

会阻止其他事务插入15的值到列t.c1,

无论这里已经有任何这样的值在列里, 因为区间在所有存在的值在范围内被锁定


区间可以跨越一个单个的index值,多个index值  甚至空的index值


区间锁是性能和并发的折中方案,并用于一些事务隔离级别 而不是其他


区间锁不能用于语句锁定记录使用一个唯一索引来搜索一个唯一的记录(这个不包含例子搜索条件只包含只是一个多列唯一索引的一部分列,在这种情况下,gap locking 仍旧存在)

例如,如果id列有一个唯一的索引,下面的语句使用一个index-record lock 用于记录id值100

它不管书是否其他sessin插入记录在之前的区间


SELECT * FROM child WHERE id = 100;


如果id没有索引或者有一个非唯一的索引,语句会lock前面的区间




它也是值得注意的 冲突的锁可以被持有一个区间通过不同的事务。

比如,事务A持有一个共享gap lock(gap S-lock) 在区间

当事务B持有一个排它的gap lock(gap X-lock) 在相同的区间。

冲突的gap locks 是被允许的 如果一个记录是从一个index被清除,

gap locks 持有记录通过不同的事务必须被合并

区间锁在InnoDB 是"纯粹抑制的",这意味着只有停止其他事务插入这个区间。

它们不阻止不同事务来占据区间锁在相同的区间,因此,一个gap X-lock 有相同的影响作为一个gap S-lock


Gap lock 可以显示的关闭,这个发生如果你改变了事务的隔离级别 为READ COMMITTED

或者让启用innodb_locks_unsafe_for_binlog  系统变量(现在是过时了)



区间锁示例:

mysql> show create table SmsTest;
+---------

+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

----------------------------------------+
| Table   | Create Table                                                                                                                                                                              

                                                                                                                                                                                                      

                                                |
+---------

+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

----------------------------------------+
| SmsTest | CREATE TABLE `SmsTest` (
  `sn` int(11) NOT NULL AUTO_INCREMENT COMMENT '自增编号',
  `phoneNo` varchar(16) NOT NULL DEFAULT '' COMMENT '电话号码',
  `channelType` int(11) DEFAULT NULL COMMENT '通道识别',
  `status` tinyint(4) NOT NULL COMMENT '短信转态,1.发送成功,2.发送失败,3.发送异常',
  PRIMARY KEY (`sn`)
) ENGINE=InnoDB AUTO_INCREMENT=201 DEFAULT CHARSET=utf8 COMMENT='短信发送成功记录表'                                      |
+---------

+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

----------------------------------------+
1 row in set (0.00 sec)

mysql> select min(sn),max(sn) from SmsTest;
+---------+---------+
| min(sn) | max(sn) |
+---------+---------+
|       1 |     200 |
+---------+---------+
1 row in set (0.00 sec)



测试1 更新列没有索引的情况下:

Session 1:

mysql> show create table SmsTest;
+---------

+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

------------------------------------------+
| Table   | Create Table                                                                                                                                                                              

                                                                                                                                                                                                      

                                                  |
+---------

+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

------------------------------------------+
| SmsTest | CREATE TABLE `SmsTest` (
  `sn` int(11) NOT NULL AUTO_INCREMENT COMMENT '自增编号',
  `phoneNo` int(16) NOT NULL ,
  `channelType` int(11) DEFAULT NULL COMMENT '通道识别',
  `status` tinyint(4) NOT NULL COMMENT '短信转态,1.发送成功,2.发送失败,3.发送异常',
  PRIMARY KEY (`sn`)
) ENGINE=InnoDB AUTO_INCREMENT=45209 DEFAULT CHARSET=utf8 COMMENT='短信发送成功记录表'                                      |
+---------

+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

------------------------------------------+
1 row in set (0.00 sec)



mysql> insert into SmsTest select sn,sn,channelType,status from SmsRecord limit 200;
Query OK, 200 rows affected (0.09 sec)
Records: 200  Duplicates: 0  Warnings: 0



mysql> start transaction;
Query OK, 0 rows affected (0.00 sec)

mysql> update SmsTest set phoneNo=111 where phoneNo=1;
Query OK, 0 rows affected (0.04 sec)
Rows matched: 0  Changed: 0  Warnings: 0


mysql> explain update SmsTest set phoneNo=111 where phoneNo=1;
+----+-------------+---------+-------+---------------+---------+---------+------+------+-------------+
| id | select_type | table   | type  | possible_keys | key     | key_len | ref  | rows | Extra       |
+----+-------------+---------+-------+---------------+---------+---------+------+------+-------------+
|  1 | SIMPLE      | SmsTest | index | NULL          | PRIMARY | 4       | NULL |  200 | Using where |
+----+-------------+---------+-------+---------------+---------+---------+------+------+-------------+
1 row in set (0.01 sec)



Session 2:

mysql> insert into SmsTest  values(201,1,1,1); ---插入Hang


mysql> delete from SmsTest where sn=99;  ---删除Hang


验证了 如果RR隔离,更新列没有索引,会锁全表




测试2 在更新列上加上索引:



mysql> create index SmsTest_idx1 on SmsTest(phoneNo);
Query OK, 0 rows affected (0.09 sec)
Records: 0  Duplicates: 0  Warnings: 0

mysql> 
mysql> 
mysql> start transaction;
Query OK, 0 rows affected (0.00 sec)

mysql> update SmsTest set phoneNo=111 where phoneNo=1;
Query OK, 1 row affected (0.00 sec)
Rows matched: 1  Changed: 1  Warnings: 0

mysql> explain update SmsTest set phoneNo=111 where phoneNo=1;
+----+-------------+---------+-------+---------------+--------------+---------+-------+------+------------------------------+
| id | select_type | table   | type  | possible_keys | key          | key_len | ref   | rows | Extra                        |
+----+-------------+---------+-------+---------------+--------------+---------+-------+------+------------------------------+
|  1 | SIMPLE      | SmsTest | range | SmsTest_idx1  | SmsTest_idx1 | 4       | const |    1 | Using where; Using temporary |
+----+-------------+---------+-------+---------------+--------------+---------+-------+------+------------------------------+
1 row in set (0.00 sec)-+-------+---------------+--------------+---------+-------+------+------------------------------+
1 row in set (0.00 sec)





Session 2:
mysql> insert into SmsTest  values(201,1,1,1);  --hang

mysql> insert into SmsTest  values(201,2,1,1);
Query OK, 1 row affected (0.00 sec)

mysql> insert into SmsTest  values(201,3,1,1);
ERROR 1062 (23000): Duplicate entry '201' for key 'PRIMARY'
mysql> insert into SmsTest  values(3,1,1);
ERROR 1136 (21S01): Column count doesn't match value count at row 1
mysql> insert into SmsTest(PhoneNo,channelType,status)  values(3,1,1);
Query OK, 1 row affected (0.01 sec)

mysql> insert into SmsTest(PhoneNo,channelType,status)  values(1,1,1); --hang


此时插入PhoneNo=1会hang 


测试区间锁:


Session 1:

mysql> start transaction;
Query OK, 0 rows affected (0.00 sec)

mysql> update SmsTest set phoneNo=111 where  phoneNo between 10 and 20;
Query OK, 11 rows affected (0.00 sec)
Rows matched: 11  Changed: 11  Warnings: 0

mysql> explain  update SmsTest set phoneNo=111 where  phoneNo between 10 and 20;
+----+-------------+---------+-------+---------------+--------------+---------+-------+------+------------------------------+
| id | select_type | table   | type  | possible_keys | key          | key_len | ref   | rows | Extra                        |
+----+-------------+---------+-------+---------------+--------------+---------+-------+------+------------------------------+
|  1 | SIMPLE      | SmsTest | range | SmsTest_idx1  | SmsTest_idx1 | 4       | const |   11 | Using where; Using temporary |
+----+-------------+---------+-------+---------------+--------------+---------+-------+------+------------------------------+
1 row in set (0.00 sec)

锁住11行



Session 2:

mysql> insert into SmsTest(PhoneNo,channelType,status)  values(1,1,1);
Query OK, 1 row affected (0.01 sec)

mysql> insert into SmsTest(PhoneNo,channelType,status)  values(2,1,1);
Query OK, 1 row affected (0.00 sec)

mysql> insert into SmsTest(PhoneNo,channelType,status)  values(3,1,1);
Query OK, 1 row affected (0.00 sec)

mysql> insert into SmsTest(PhoneNo,channelType,status)  values(4,1,1);
Query OK, 1 row affected (0.00 sec)

mysql> insert into SmsTest(PhoneNo,channelType,status)  values(5,1,1);
Query OK, 1 row affected (0.00 sec)

mysql> insert into SmsTest(PhoneNo,channelType,status)  values(6,1,1);
Query OK, 1 row affected (0.00 sec)

mysql> insert into SmsTest(PhoneNo,channelType,status)  values(7,1,1);
Query OK, 1 row affected (0.01 sec)

mysql> insert into SmsTest(PhoneNo,channelType,status)  values(8,1,1);
Query OK, 1 row affected (0.00 sec)

mysql> insert into SmsTest(PhoneNo,channelType,status)  values(9,1,1);  --hang


mysql> insert into SmsTest(PhoneNo,channelType,status)  values(10,1,1); --hang

mysql> insert into SmsTest(PhoneNo,channelType,status)  values(11,1,1);--hang 

mysql> insert into SmsTest(PhoneNo,channelType,status)  values(12,1,1); --hang

mysql> insert into SmsTest(PhoneNo,channelType,status)  values(13,1,1); --hang


mysql> insert into SmsTest(PhoneNo,channelType,status)  values(14,1,1); --hang


mysql> insert into zjzc.SmsTest(PhoneNo,channelType,status)  values(15,1,1); --hang


mysql> insert into zjzc.SmsTest(PhoneNo,channelType,status)  values(16,1,1); --hang

mysql> insert into zjzc.SmsTest(PhoneNo,channelType,status)  values(17,1,1);--hang

mysql> insert into zjzc.SmsTest(PhoneNo,channelType,status)  values(19,1,1); --hang


mysql> insert into zjzc.SmsTest(PhoneNo,channelType,status)  values(20,1,1);  --hang


mysql> insert into zjzc.SmsTest(PhoneNo,channelType,status)  values(21,1,1);
Query OK, 1 row affected (0.03 sec)

mysql> insert into zjzc.SmsTest(PhoneNo,channelType,status)  values(22,1,1);
Query OK, 1 row affected (0.00 sec)

mysql> insert into zjzc.SmsTest(PhoneNo,channelType,status)  values(23,1,1);
Query OK, 1 row affected (0.00 sec)

转载于:https://www.cnblogs.com/zhaoyangjian724/p/6199086.html

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值