gap锁(间隙锁)
间隙锁实质上是对索引前后的间隙上锁,不对索引本身上锁。
根据检索条件向左寻找最靠近检索条件的记录值A,作为左区间,向右寻找最靠近检索条件的记录值B作为右区间,即锁定的间隙为(A,B)。
间隙锁的目的是为了防止幻读,其主要通过两个方面实现这个目的:
(1)防止间隙内有新数据被插入。
(2)防止已存在的数据,更新成间隙内的数
我们这里会将不同情况下间隙锁的展示,字母,以及数字
首先,我们需要明白几个条件
一、这个是针对事务下的
二、这个是需要索引支持
三、索引是非唯一的,也就是index
数字
创建表
create table data(list1 int(5),list2 int(5),index(list1));
插入数据
insert into data(list1,list2) values(3,104);
insert into data(list1,list2) values(6,104);
insert into data(list1,list2) values(8,104);
mysql> select * from data;
+-------+-------+
| list1 | list2 |
+-------+-------+
| 3 | 104 |
| 6 | 104 |
| 8 | 104 |
+-------+-------+
5 rows in set (0.00 sec)
好了,我们来解释并验证一下
一、数字之间有顺序
所谓间隙锁,也就是将你指定的,且带有索引的那一行以及旁边的两行锁起来,我们来想一想为什么这样就不会出现幻数了,比如说,我现在想要改6这行的104,首先,我们查看6
mysql> select * from data where list1=6;
+-------+-------+
| list1 | list2 |
+-------+-------+
| 6 | 104 |
+-------+-------+
1 row in set (0.00 sec)
所谓出现幻数就是,我们开启事务之后,我们查这个6,是只有一行,但是,突然间有个傻逼又加了一行,事务查询就变成
mysql> select * from data where list1=6;
+-------+-------+
| list1 | list2 |
+-------+-------+
| 6 | 104 |
| 6 | 105 |
+-------+-------+
1 row in set (0.00 sec)
我们自然知道是多加了一行,但是事务处理的时候它自己整不明白啊,这个时候就会出现事务要修改的时候,发现有两行数据,明明刚刚才只有一条而已
这时候就体现了间隙锁的威力了
我们把事务开启
mysql> begin;
Query OK, 0 rows affected (0.00 sec)
mysql> update data set list2=105 where list1=6;
Query OK, 1 row affected (0.00 sec)
Rows matched: 1 Changed: 1 Warnings: 0
另一个会话进行插入一个6的数据
mysql> insert into data(list1,list2) values(6,202);
可以看到,这玩意卡住了,它正在等待事务的结束,我们继续插入周边的数据
mysql> insert into data(list1,list2) values(7,202);
依旧是卡住的
mysql> insert into data(list1,list2) values(5,202);
我们插个8进去,成功了
mysql> insert into data(list1,list2) values(8,202);
Query OK, 1 row affected (0.00 sec)
插个3进去,卡住了
mysql> insert into data(list1,list2) values(3,202);
这就是有趣的地方了,也是比较难理解的地方,我们所谓索引,并不是我们看到的那么简单,我们使用select看到的顺序是3 6 8,也就是说明3,4,6,7都在这个集合里面,与这几个相关的都是无法正常插入的,为什么8可以呢,我们想一想,插入数据是插在下面的,那是不是就不是在这个缝隙里面了
有些机灵鬼就要说了,你这数据是并排起来的,那如果乱来呢,我们依旧来验证一下,我又创建了data1
二、数字之间没有顺序
mysql> select * from data1;
+-------+-------+
| list1 | list2 |
+-------+-------+
| 6 | 104 |
| 3 | 104 |
| 8 | 104 |
+-------+-------+
3 rows in set (0.00 sec)
mysql> insert into data(list1,list2) values(3,202);
^C -- query aborted
ERROR 1317 (70100): Query execution was interrupted
mysql> insert into data(list1,list2) values(8,202);
Query OK, 1 row affected (0.00 sec)
mysql> insert into data(list1,list2) values(5,202);
^C -- query aborted
ERROR 1317 (70100): Query execution was interrupted
你会发现,结果会和之前一样,也就是说,固定是根据你select出来,你看到的数字左右两边的集合,不管你的顺序是什么,索引会帮你排号它们
欸,那边界呢
三、边界数字
mysql> update data1 set list2=106 where list1=8;
Query OK, 2 rows affected (0.00 sec)
Rows matched: 2 Changed: 2 Warnings: 0
我们这边使用边界数8
插入一些数字
mysql> insert into data1(list1,list2) values(1,202);
Query OK, 1 row affected (0.00 sec)
mysql> insert into data1(list1,list2) values(7,202);
^C^C -- query aborted
ERROR 1317 (70100): Query execution was interrupted
mysql> insert into data1(list1,list2) values(100,202);
^C^C -- query aborted
ERROR 1317 (70100): Query execution was interrupted
发现只有小于6的可以插入
我们可以整理一下
mysql> select * from data;
+-------+-------+
| list1 | list2 |
+-------+-------+
| 3 | 104 |
| 6 | 104 |
| 8 | 104 |
+-------+-------+
一、
我们选择6的时候,6作为中间数被
锁定范围为[3,6]U[6,8)
即便顺序不一样也是这样的
二、
我们选择边界数的时候,比如8
锁定范围为[6,8]U[8,∞)
我们选择边界数3的时候,
锁定范围为(∞,3]U[3,6)
字母
不是我挑了好讲的数字来说,而是两者是基本上一样的
字母也有字母的范围,[Aa-Zz]为什么这么写,MySQL是大小写不敏感
mysql> select * from data3;
+-------+-------+
| list1 | list2 |
+-------+-------+
| a | asad |
| c | asad |
| F | asad |
+-------+-------+
3 rows in set (0.00 sec)
新表,有大小写
开始验证
一、单字母验证
创建事务
mysql> begin;
Query OK, 0 rows affected (0.00 sec)
mysql> update data3 set list2='dasd' where list1='c';
Query OK, 1 row affected (0.00 sec)
Rows matched: 1 Changed: 1 Warnings: 0
插入验证
mysql> insert into data3(list1,list2) values('d','asd');
^C^C -- query aborted
ERROR 1317 (70100): Query execution was interrupted
mysql> insert into data3(list1,list2) values('D','asd');
^C^C -- query aborted
ERROR 1317 (70100): Query execution was interrupted
mysql> insert into data3(list1,list2) values('E','asd');
^C^C -- query aborted
ERROR 1317 (70100): Query execution was interrupted
mysql> insert into data3(list1,list2) values('F','asd');
Query OK, 1 row affected (0.00 sec)
看到了吗,只有F能够插进去
这还需要解释吗?跟上面数字的8有什么不同?也就是有大小写而已,大小写不敏感,因此是一样的
我们现在需要想一下,在数字里面8和88是有对比的,因为88大过8,但是F和FF是不一样的,这两个可没有办法比较呀ascll码也不能这样加吧
二、多字母验证
事务开启
mysql> begin;
Query OK, 0 rows affected (0.00 sec)
mysql> update data3 set list2='dasd' where list1='c';
Query OK, 0 rows affected (0.00 sec)
Rows matched: 1 Changed: 0 Warnings: 0
插入验证
mysql> insert into data3(list1,list2) values('EE','asd');
^C^C -- query aborted
ERROR 1317 (70100): Query execution was interrupted
mysql> insert into data3(list1,list2) values('aa','asd');
^C^C -- query aborted
ERROR 1317 (70100): Query execution was interrupted
mysql> insert into data3(list1,list2) values('Avdf','asd');
^C^C -- query aborted
ERROR 1317 (70100): Query execution was interrupted
mysql> insert into data3(list1,list2) values('fsdd','asd');
Query OK, 1 row affected (0.00 sec)
看到了吗,是不准的,也就是说明,字母的验证是根据首字母的
好了,GAP间隙锁验证结束