mysql innodb间隙锁示例

innodb的记录锁介绍原文见 http://dev.mysql.com/doc/refman/5.1/en/innodb-record-level-locks.html

innodb的记录锁有三种类型:

  • 记录锁:是加在索引记录上的。
  • 间隙锁:对索引记录间的范围加锁,或者加在最后一个索引记录的前面或者后面
  • Next-key锁:记录锁和间隙锁的组合,间隙锁锁定记录锁之前的范围

间隙锁主要是防止幻象读,用在Repeated-Read(简称RR)隔离级别下。在Read-Commited(简称RC)下,一般没有间隙锁(有外键情况下例外,此处不考虑)。间隙锁还用于statement
based replication

间隙锁有些副作用,如果要关闭,一是将会话隔离级别改到RC下,或者开启
innodb_locks_unsafe_for_binlog(默认是OFF)。

间隙锁只会出现在辅助索引上,唯一索引和主键索引是没有间隙锁。间隙锁(无论是S还是X)只会阻塞insert操作。

下面演示一种因为间隙锁而出现等待的情形。


准备脚本

CREATE TABLE `xdual` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `x`
timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `v` int(11) DEFAULT
NULL,
  PRIMARY KEY (`id`),
  KEY `idx_x` (`x`),
  KEY `idx_v`
(`v`)
) ENGINE=InnoDB AUTO_INCREMENT=70 DEFAULT CHARSET=utf8;

root@localhost : test 09:39:47> select
* from xdual;
+----+---------------------+------+
| id |
x                   | v    |
+----+---------------------+------+
|  2 |
2012-04-19 20:25:40 |    1 |
|  4 | 2012-04-18 00:53:58 |    3 |
|  6 |
2012-04-18 00:54:00 |    5 |
|  8 |
2012-04-18 18:23:16 |    7 |
| 10 | 2012-04-18 00:54:03 |    2 |
|
12 | 2012-04-18 02:26:13 |    4 |
| 14 | 2012-04-18 00:54:06 |    6 |
| 15
| 2012-04-18 02:26:13 |    4 |
| 16 |
2012-04-18 18:24:14 |    7 |
| 18 | 2012-04-18 00:54:10 |    8 |
| 22 |
2012-04-18 15:12:08 |   18 |
| 26 | 2012-04-18 18:23:16 |    7 |
|
34 | 2012-04-18 02:30:09 |    4 |
+----+---------------------+------+
13
rows in set (0.03 sec)


测试场景

#sess1

root@localhost : test 09:45:40> set
autocommit=0;
Query OK, 0 rows affected (0.00 sec)

root@localhost : test 09:46:14> set
tx_isolation='REPEATABLE-READ';
Query OK, 0 rows affected (0.00 sec)

root@localhost : test 09:46:22> delete
from xdual where v=8;
Query OK, 1 row affected (0.01 sec)

root@localhost : test 09:46:50>

#sess2

root@localhost : test 09:40:20> set
tx_isolation='REPEATABLE-READ';
Query OK, 0 rows affected (0.00 sec)

root@localhost : test 09:46:30> set
autocommit=0;
Query OK, 0 rows affected (0.00 sec)

root@localhost : test 09:46:33> insert
into xdual values(11,now(),7);
Query OK, 1 row affected (0.00 sec)

root@localhost : test 09:47:08> insert
into xdual values(31,now(),7);
(BLOCKING)

此时用innotop查看锁分布

_________________________________________ InnoDB Locks
__________________________________________
ID        Type    Waiting  Wait  
Active  Mode  DB    Table  Index    Ins Intent  Special       
24066093  RECORD        1  01:11   01:22  X     test  xdual 
idx_v             1  gap before rec
24066093  TABLE         0  01:11  
01:22  IX    test  xdual                    0                
24066093 
RECORD        1  01:11   01:22  X     test  xdual  idx_v             1  gap
before rec
24066090  TABLE         0  00:00   01:40  IX    test 
xdual                    0                
24066090  RECORD        0 
00:00   01:40  X     test  xdual  idx_v             0                

24066090  RECORD        0  00:00   01:40  X     test  xdual 
PRIMARY           0  rec but not gap
24066090  RECORD        0  00:00  
01:40  X     test  xdual  idx_v             0  gap before rec
Press any key
to continue

很快会话2就timeout

ERROR 1205 (HY000): Lock wait timeout exceeded; try
restarting transaction
root@localhost : test 09:49:20>


分析:

#sess1: delete from xdual where v=8;
这个sql锁定的范围是
(7,18)。此时,#sess2如果想插入一笔v=8的数据,肯定被blocking,但是插入一笔v=7的数据,就要看插入记录的位置是否在这个区间(7,18)以内。
root@localhost : test 10:06:35> select *
from xdual where v=7;
+----+---------------------+------+
| id |
x                   | v    |
+----+---------------------+------+
|  8 |
2012-04-18 18:23:16 |    7 |
| 16 | 2012-04-18 18:24:14 |    7 |
| 26 |
2012-04-18 18:23:16 |    7 |
+----+---------------------+------+
3 rows in
set (0.00 sec)

insert into xdual values(11,now(),7); 要插入的位置在
id=16和id=26之间,不在上面那个区间内,所以不被blocking
insert into xdual values(31,now(),7);
这个就在被锁定的区间内,所以被阻塞。
同理,#sess2 下面的sql也会被阻塞

root@localhost : test 10:06:40> insert
into xdual(x,v) values(now(),9);
(BLOCKING)

root@localhost : test 10:06:40> insert
into xdual(x,v) values(now(),9);
ERROR 1205 (HY000): Lock
wait timeout exceeded; try restarting transaction
root@localhost : test 10:10:50> insert into
xdual(id,x,v) values(20,now(),18);
(BLOCKING)

root@localhost
: test 10:10:50> insert into xdual(id,x,v) values(20,now(),18);
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting
transaction
root@localhost : test 10:14:35>


时间: 2025-01-01 02:46:41

mysql innodb间隙锁示例的相关文章

Mysql innodb 间隙锁

前段时间系统老是出现insert死锁,很是纠结.经过排查发现是间隙锁!间隙锁是innodb中行锁的一种, 但是这种锁锁住的却不止一行数据,他锁住的是多行,是一个数据范围.间隙锁的主要作用是为了防止出现幻读,但是它会把锁定范围扩大,有时候也会给我们带来麻烦,我们就遇到了. 在数据库参数中, 控制间隙锁的参数是:innodb_locks_unsafe_for_binlog, 这个参数默认值是OFF, 也就是启用间隙锁, 他是一个bool值, 当值为true时表示disable间隙锁.那为了防止间隙锁

巧用MySQL InnoDB引擎锁机制解决死锁问题

最近,在项目开发过程中,碰到了数据库死锁问题,在解决问题的过程中,笔者对MySQL InnoDB引擎锁机制的理解逐步加深. 案例如下: 在使用Show innodb status检查引擎状态时,发现了死锁问题: *** (1) TRANSACTION: TRANSACTION 0 677833455, ACTIVE 0 sec, process no 11393, OS thread id 278546 starting index read mysql tables in use 1, loc

RDS for MySQL InnoDB 行锁等待和锁等待超时的处理

RDS for MySQL InnoDB 行锁等待和锁等待超时的处理   1. InnoDB 引擎表行锁等待和等待超时发生的场景 2.InnoDB 引擎行锁等待情况的处理 2.1 InnoDB 行锁等待超时参数 innodb_lock_wait_timeout 2.2 大量行锁等待和行锁等待超时的处理 1. InnoDB 引擎表行锁等待和等待超时发生的场景 当一个 RDS for MySQL 连接会话等待另外一个会话持有的互斥行锁时,会发生 InnoDB 引擎表行锁等待情况. 通常情况下,持有该

MYSQL InnoDB表锁

InnoDB锁问题 InnoDB与MyISAM的最大不同有两点:一是支持事务(TRANSACTION):二是采用了行级锁.行级锁与表级锁本来就有许多不同之处,另外,事务的引入也带来了一些新问题.下面我们先介绍一点背景知识,然后详细讨论InnoDB的锁问题. 2.并发事务处理带来的问题 相对于串行处理来说,并发事务处理能大大增加数据库资源的利用率,提高数据库系统的事务吞吐量,从而可以支持更多的用户.但并发事务处理也会带来一些问题,主要包括以下几种情况.      更新丢失(ost Update):

MySQL中InnoDB的间隙锁问题_Mysql

 在为一个客户排除死锁问题时我遇到了一个有趣的包括InnoDB间隙锁的情形.对于一个WHERE子句不匹配任何行的非插入的写操作中,我预期事务应该不会有锁,但我错了.让我们看一下这张表及示例UPDATE.   mysql> SHOW CREATE TABLE preferences \G *************************** 1. row *************************** Table: preferences Create Table: CREATE TAB

MySQL数据库之锁的详解

锁是计算机协调多个进程或线程并发访问某一资源的机制.在数据库中,除传统的计算资源(如CPU.RAM.I/O等)的争用以外,数据也是一种供许多用户共享的资源.如何保证数据并发访问的一致性.有效性是所有数据库必须解决的一个问题,锁冲突也是影响数据库并发访问性能的一个重要因素.从这个角度来说,锁对数据库而言显得尤其重要,也更加复杂.本章我们着重讨论MySQL锁机制的特点,常见的锁问题,以及解决MySQL锁问题的一些方法或建议. MySQL锁概述 相对其他数据库而言,MySQL的锁机制比较简单,其最显著

mysql-MYSQL INNODB表锁和行锁的问题

问题描述 MYSQL INNODB表锁和行锁的问题 Id是主键.以下语句分别是行锁还是表锁? 第一句:update Table set X=1 where Id IN (1,2,4,7); 第二句:update Table set X=1 where Id Between 1 AND 10; 第三句:update Table set X=1 where Id>=1 AND Id<100; 解决方案 这些都是行锁,只有lock table语句innodb才会申请表锁

MySQL InnoDB之事务与锁详解

引题:为何引入事务? 1>.数据完整性 2>.数据安全性 3>.充分利用系统资源,提高系统并发处理的能力 1. 事务的特征 事务具有四个特性:原子性(Atomiocity).一致性(Consistency).隔离性(Isolation)和持久性(Durability),这四个特性简称ACID特性. 1.1原子性 事务是数据库的逻辑工作单位,事务中包括的所有操作要么都做,要么都不做. 1.2 一致性 事务执行的结果必须是使数据库从一个一致性的状态变到另外一个一致性状态. 1.3 隔离性 一

mysql事务和锁InnoDB(转)

背景   MySQL/InnoDB的加锁分析,一直是一个比较困难的话题.我在工作过程中,经常会有同事咨询这方面的问题.同时,微博上也经常会收到MySQL锁相关的私信,让我帮助解决一些死锁的问题.本文,准备就MySQL/InnoDB的加锁问题,展开较为深入的分析与讨论,主要是介绍一种思路,运用此思路,拿到任何一条SQL语句,都能完整的分析出这条语句会加什么锁?会有什么样的使用风险?甚至是分析线上的一个死锁场景,了解死锁产生的原因.   注:MySQL是一个支持插件式存储引擎的数据库系统.本文下面的