ICode9

精准搜索请尝试: 精确搜索
首页 > 数据库> 文章详细

MySQL的间隙锁

2021-07-06 11:03:05  阅读:198  来源: 互联网

标签:name 间隙 lock py gas session MySQL id


 

0x01:什么是间隙锁

        间隙锁(Gap Lock)是Innodb在可重复读提交下为了解决幻读问题时引入的锁机制。当用范围条件而不是相等条件检索数据,并请求共享或排他锁时,InnoDB会给符合条件的已有数据记录的索引项加锁;对于键值在条件范围内但不存在的记录,叫做“间隙(GAP)”,InnoDB也会对这些“间隙”进行加锁,这种锁机制就是所谓的间隙锁(NEXT-KEY)锁。

 

0x02:间隙锁引起的问题

       因为执行SELECT语句中,如果通过范围查找的话,间隙锁会锁定整个范围内所有的索引键值,即使这个键值并不存在。这个就是间隙锁最致命的缺点,就是当锁定一个范围键值之后,即使某些不存在的键值也会被无辜的锁定,而造成在锁定的时候无法插入锁定值范围内的任何数据,在某些场景下这可能会针对性造成很大的危害。

 

0x03:间隙锁例子

建表:

CREATE TABLE `gas_lock_tab` (
`id`  bigint(20) NOT NULL COMMENT 'id' ,
`user_name_py`  int(11) NOT NULL COMMENT '用户姓名拼音' ,
PRIMARY KEY (`id`),
INDEX `usernameIndex` (`user_name_py`) USING BTREE 
)
ENGINE=InnoDB
DEFAULT CHARACTER SET=utf8 COLLATE=utf8_general_ci
ROW_FORMAT=DYNAMIC
;

插入数据:

INSERT INTO `gas_lock_tab`(`id`, `user_name_py`) VALUES (1, 'huangjinjin');
INSERT INTO `gas_lock_tab`(`id`, `user_name_py`) VALUES (3, 'java乐园');
INSERT INTO `gas_lock_tab`(`id`, `user_name_py`) VALUES (5, '架构师知音');
INSERT INTO `gas_lock_tab`(`id`, `user_name_py`) VALUES (8, 'java狂人');   

插入数据后查询:

mysql> select * from gas_lock_tab;
+----+--------------+
| id | user_name_py |
+----+--------------+
|  1 | huangjinjin  |
|  3 | java乐园     |
|  8 | java狂人     |
|  5 | 架构师知音    |
+----+--------------+
4 rows in set  

      注意表中的数据,id字段是int型,包含1,3,5,8;当然1到8中间,缺少连续的id:2,4,6,7,而没有连续下来。一般在表里的主键id最好是连续的,方便索引;所谓的删除其实是做逻辑删除,只是做了状态更改,而不做物理删除。

 

打开两个Mysql终端,分别设置autocommit为0(手动提交事务),也就是关闭自动提交功能,事务隔离级别处于可重复读状态。

session 1:

mysql> set autocommit=0;
Query OK, 0 rows affected

 

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

session 2:

mysql> set autocommit=0;
Query OK, 0 rows affected

 

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

 

session 1 执行update操作,执行成功

mysql> update gas_lock_tab set user_name_py = '1234' where id > 1 and id < 5;
Query OK, 0 rows affected
Rows matched: 1  Changed: 0  Warnings: 0

也就是对3这四条数据做修改。注意这里没有id为2和4的记录;在第二个终端执行insert操作,发现被阻塞。

insert into gas_lock_tab values (2,'it大佬');

 

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

按说在InnoDB的行级锁,两个不同的终端操作不同的行数据,不会造成阻塞,但是阻塞出现了。达到超时时间后,seesion 2出现如下错误:

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

另外,如果在session 2的插入语句没有超时之前,对session 1进行 commit操作,则会发现session 2也会执行操作成功。

session 1 commit操作:

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

session 2出现的结果:

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

这时对session 1做commit操作,发现update和inster操作都生效了。

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

关注我

每天进步一点点

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

标签:name,间隙,lock,py,gas,session,MySQL,id
来源: https://blog.51cto.com/u_13538361/2987236

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有