前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >innodb锁机制探究(二)---间隙锁(1)

innodb锁机制探究(二)---间隙锁(1)

作者头像
AsiaYe
发布2019-11-06 17:15:52
1.1K0
发布2019-11-06 17:15:52
举报
文章被收录于专栏:DBA随笔DBA随笔
//

innodb锁机制探究(二)---间隙锁

//

Innodb中的锁算法

innodb中常用的锁算法一般有三种,分别是

1、Record lock,行记录锁

2、Gap Lock,间隙锁

3、Next-key Lock,next key锁

其中Next key锁是Gap锁和Record锁的结合,他锁定的是一个范围,并且锁定记录本身。

也就是说,next key锁不是一个单独的锁,就我理解,它其实是一个概念,这个概念是由上面两个锁的概念组合而来的。记录锁很好理解,就是对某个记录的锁定,今天我们主要说说间隙锁。

间隙锁简介

间隙锁定是锁定索引记录之间的间隙,或者锁定第一个和最后一个记录之间的间隙。组织其他事务将值插入到这个间隙中来,间隙可能跨越单个索引值,多个索引值,也有可能为空。

可重复读级别下才会有间隙锁!!!!

可重复读级别下才会有间隙锁!!!!

可重复读级别下才会有间隙锁!!!!

间隙锁定之间不存在冲突关系,这点也很重要。如果一个事务对某个间隙中间加了锁,那么其他事务也可以在这个间隙中加锁,这些操作不冲突。他的存在,仅仅是为了防止其他事务在这个间隙中插入记录。

间隙锁实例

为了实现间隙锁,我们可以通过以下的例子来查看,首先我们创建一个表,包含id和age两个字段,在age上创建一般的索引,创建语句如下,然后我们插入一些记录:

代码语言:javascript
复制
mysql--dba_admin@127.0.0.1:yeyztest ::>>show create table child\G         
*************************** 1. row ***************************
       Table: child
Create Table: CREATE TABLE `child` (
  `id` int() NOT NULL,
  `age` int() NOT NULL,
  PRIMARY KEY (`id`),
  KEY `idx_age` (`age`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8
 row in set (0.00 sec)


mysql--dba_admin@127.0.0.1:yeyztest ::>>truncate table child;
Query OK,  rows affected (0.01 sec)

mysql--dba_admin@127.0.0.1:yeyztest ::>>insert into child values (,); 
Query OK,  row affected (0.00 sec)

mysql--dba_admin@127.0.0.1:yeyztest ::>>insert into child values (,);
Query OK,  row affected (0.00 sec)

mysql--dba_admin@127.0.0.1:yeyztest ::>>insert into child values (,);
Query OK,  row affected (0.00 sec)

mysql--dba_admin@127.0.0.1:yeyztest ::>>insert into child values (,);
Query OK,  row affected (0.00 sec)

创建表child,然后插入记录10,11,13,20这四条记录,然后我们开始测试间隙锁定,如下:

我们可以发现,插入age等于9或者21的记录可以插入,其他的记录都插入不进去,原因是我们的表中原来的记录是10,11,13,20,那么这个表的间隙就被分成了:

(negative infinity,10]

(10,11],

(11,13],

(13,20],

(20,positive infinity)

需要注意的是,negative infonity和positive infinity是最大记录和最小记录,如果对这两个记录不明确的话,不要紧,可以查看我们4月9号的文章,里面有讲到innodb数据页结构里面的最小记录和最大记录。

因为我们在session 1上锁定了id=13的记录,所以在session B上就不能访问11-13以及13=20之间的记录了,也就是说间隙锁就是(11,20),而本身10和11这两条记录都存在,所以在间隙前面可以插入的最大记录就是9,间隙后面可以插入的最大记录是21.

现在我们知道,在整个插入的过程中发生了锁,我们是用show engine innodb status来查看锁信息,如下:

代码语言:javascript
复制
------------
TRANSACTIONS
------------
Trx id counter 
Purge done for trx's n:o < 1329883 undo n:o < 0 state: running but idle
History list length 2305
LIST OF TRANSACTIONS FOR EACH SESSION:
---TRANSACTION 1329878, ACTIVE 19 sec inserting
mysql tables in use 1, locked 1
LOCK WAIT 2 lock struct(s), heap size 1136, 1 row lock(s), undo log entries 1
MySQL thread id 3938833, OS thread handle 140584442394368, query id 105210346 127.0.0.1 dba_admin update
INSERT INTO child (id,age) VALUES (12,12)
------- TRX HAS BEEN WAITING 19 SEC FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 168 page no 4 n bits 72 index idx_age of table `yeyztest`.`child` trx id 1329878 lock_mode X locks gap before rec insert intention waiting
------------------
---TRANSACTION 1329859, ACTIVE 52 sec
4 lock struct(s), heap size 1136, 3 row lock(s)
MySQL thread id 3938791, OS thread handle 140584421222144, query id 105210793 127.0.0.1 dba_admin starting
show engine innodb status

可以看到红色的部分就说明了存在gap锁的信息,而且给出了trx的id值,我们还可以使用之前讲过的information_schema中的innodb_trx和innodb_locks表来查看相关的锁信息,这里不再赘述。

间隙锁导致的死锁问题

因为间隙锁之间不会产生影响,可以同时存在,所以就有了产生死锁的可能,我们看下面这个例子,首先,经过上面的操作,我们现在表里面的数据变成了:

代码语言:javascript
复制
mysql:yeyztest ::>>select * from child;
+----+-----+
| id | age |
+----+-----+
|   |    |
|  |   |
|  |   |
|  |   |
|  |   |
|  |   |
+----+-----+
 rows in set (0.00 sec)

然后我们进行如下的操作:

可以看到,当我们锁定age=15的值的时候,由于这个值不存在,所以锁定了区间(13,20),而在session B上也锁定了这个区间,由于间隙锁不存在冲突,所以session B这个语句执行成功。也就是说,两个会话都锁定了这个区间,此时我们在session A上插入age=15的记录,可以发现锁住了,迟迟没有操作结果,而在session B上插入age=15的记录,则直接提示deadlock found,此时session A上的语句执行成功,也就是说这两个会话上的insert操作互相相成了死锁,innodb此时进行了优化,所以才可以输出最终的结果。

简单总结一下

1、间隙锁锁定的是某个索引记录之前和之后的一个间隙范围。

2、间隙锁之间互不影响,可以在锁定的区间再次添加间隙锁。

3、间隙锁可能造成死锁

4、间隙锁是在RR隔离级别下特有的

5、间隙锁只影响一般索引,对于唯一索引和主键,情况有些许不同,下篇文章我们会着重分析。

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2019-05-28,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 DBA随笔 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
云数据库 SQL Server
腾讯云数据库 SQL Server (TencentDB for SQL Server)是业界最常用的商用数据库之一,对基于 Windows 架构的应用程序具有完美的支持。TencentDB for SQL Server 拥有微软正版授权,可持续为用户提供最新的功能,避免未授权使用软件的风险。具有即开即用、稳定可靠、安全运行、弹性扩缩等特点。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档