Innodb锁机制探究 - 间隙锁

Innodb中的锁算法

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

1、Record lock,行记录锁

2、Gap Lock,间隙锁

3、Next-key Lock,next key锁

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

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

间隙锁简介

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

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

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

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

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

间隙锁实例

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

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


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

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

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

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

mysql--dba_admin@127.0.0.1:yeyztest 10:13:48>>insert into child values (20,20);
Query OK, 1 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来查看锁信息,如下:

------------
TRANSACTIONS
------------
Trx id counter 1329883
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表来查看相关的锁信息,这里不再赘述。

间隙锁导致的死锁问题

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

mysql:yeyztest 11:29:19>>select * from child;
+----+-----+
| id | age |
+----+-----+
|  9 |   9 |
| 10 |  10 |
| 11 |  11 |
| 13 |  13 |
| 20 |  20 |
| 21 |  21 |
+----+-----+
6 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、间隙锁只影响一般索引,对于唯一索引和主键,情况有些许不同,下篇文章我们会着重分析。

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

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值