Gap 锁
14.3.1 InnoDB Locking InnoDB 锁 本章节描述InnoDB 使用的锁类型: Shared and Exclusive Locks Intention Locks Record Locks Gap Locks Next-Key Locks Insert Intention Locks AUTO-INC Locks Shared and Exclusive Locks 共享锁和排他锁: InnoDB 实现 标准的row-level locking 这里有两种类型的lcoks, shared (S) locks and exclusive (X) locks. 1.共享锁(S锁) 允许事务持有lock来读取一条记录 2.一个exclusive (X) lock 允许事务持有锁来更新或者删除一条记录 如果事务T1持有一个共享锁在记录r上, 那么另外一个事务T2 请求一个lock 在记录r上是如下处理的: T2 请求一个S锁会被立即授予,因此,T1和T2 都持有S锁在记录r上 T2请求一个X锁 不能被立即授予 如果一个事务T1持有1个排他锁在记录r上, 那么另外一个事务T2请求任何类型的锁在记录r上 都不能立即被授权,代替的是 事务T2 需要等待事务T1释放记录r上的锁。 Intention Locks 意向锁: InnoDB 支持多种丽都的锁 允许row-level locks and locks 在整个表上并存。 为了使锁在多个粒度级别可用, 额外类型的锁被称为意向锁被使用。意向锁是表级锁 在InnoDB里 表明哪种类型的锁(共享或者排他) 一个事务将随后需要对于表里的一行记录。 这里有两种类型的意向锁用于InnoDB(假设事务T 已经请求了一个lock) 1. Intention shared (IS): 事务T想要设置S锁在表t的单独行上 2.Intention exclusive (IX): 事务T想要设置X锁在那些行上。 比如,SELECT ... LOCK IN SHARE MODE 设置一个IS 锁和 SELECT ... FOR UPDATE 设置一个IX锁 意向锁协议如下: 1.在一个事务能获取一个S锁 在表t的一条记录上,它必须首选获得一个IS或者更强的锁 2. 在一个事务可以获得一个X锁 在一条记录上,它必须首选获得一个IX锁在表t上 这些规则可以很方便地通过以下的锁类型兼容性矩阵。 X IX S IS
X Conflict Conflict Conflict Conflict
IX Conflict Compatible Conflict Compatible
S Conflict Conflict Compatible Compatible
IS Conflict Compatible Compatible Compatible 一个锁被授权来请求事务如果它是和存在的锁兼容的, 如果它和存在的锁冲突就不会授权。 一个事务等待直到冲突存在的锁被释放。 如果一个lock 和一个存在的锁冲突,那么不能被授权 因为它会导致死锁 因此,意向锁不会堵塞任何除非全表请求(比如 LOCK TABLES ... WRITE) IX 和IS 锁的主要目的是显示 有人锁定了一行,或者将锁定一行。 MySQL官网上有个死锁的例子,但分析得过于概括,这里我们详细分析一下。 首先,会话S1以SELECT * FROM t WHERE i = 1 LOCK IN SHARE MODE查询,该语句首先会对t表加IS锁,接着会对数据(i = 1)
加S锁。 mysql> select * from test where id=1 LOCK IN SHARE MODE;
+------+------+
| id | name |
+------+------+
| 1 | b |
+------+------+
1 row in set (0.00 sec) 接着,会话S2执行DELETE FROM t WHERE i = 1,该语句尝试对t表加IX锁,由于IX锁与IS锁是兼容的,所以成功对t表加IX锁。 接着继续对数据(i = 1)加X锁,但数据已经被会话S1事务加了S锁了,所以会话S2等待。 mysql> delete from test where id=1; --HANG 接着,会话S1也执行DELETE FROM t WHERE i = 1,该语句首先对t表加IX锁,虽然会话S2已经对t表加了IX锁,但IX锁与IX锁之间
是兼容的,所以成功对t表加上IX锁。 接着会话S1会对数据(i = 1)加X锁,此时发现会话S2占有的IX锁与X锁不兼容,所以会话S1也等待。就这样,会话S1等S2释放IX
锁,而会话S2等S1释放S锁,从而死锁发生。 会话S2 产生死锁:
mysql> delete from test where id=1;
ERROR 1213 (40001): Deadlock found when trying to get lock; Record Locks 记录锁:
一个record lock 是lock在一个Index record.比如, SELECT c1 FOR UPDATE FROM t WHERE c1 = 10; 阻止任何其他事物来插入,更新或者删除t1.c1=10的记录 Record locks 总是lock index 记录,尽管一个表时定义为没有索引。 对于这样的请求, InnoDB 创建一个隐含的 clustered index和使用这个index 用于record locking. Gap Locks 区间锁 一个gap lock 是在一个区间在Index records 之间, 或者一个区间在第一个之前或者最后一个之后。 比如, SELECT c1 FOR UPDATE FROM t WHERE c1 BETWEEN 10 and 20; 阻止其他事物插入值15到 c1列, 不管时候已经有这样的值在列里,因为Gap在存在的值之间 会被锁定 CREATE TABLE `t1` (
`sn` int(11) NOT NULL AUTO_INCREMENT,
`id` int(11) DEFAULT NULL,
`info` varchar(40) DEFAULT NULL,
PRIMARY KEY (`sn`)
) ENGINE=InnoDB AUTO_INCREMENT=235 DEFAULT CHARSET=utf8 session 1:
mysql> select * from t1;
+-----+------+------+
| sn | id | info |
+-----+------+------+
| 235 | 1 | a1 |
| 236 | 2 | a2 |
| 237 | 3 | a3 |
| 238 | 4 | a4 |
| 239 | 5 | a5 |
| 240 | 6 | a6 |
| 241 | 7 | a7 |
| 242 | 8 | a8 |
| 243 | 9 | a9 |
| 244 | 10 | a10 |
+-----+------+------+
10 rows in set (0.00 sec) mysql> select * from t1 where id BETWEEN 10 and 20 for update
-> ;
+-----+------+------+
| sn | id | info |
+-----+------+------+
| 244 | 10 | a10 |
+-----+------+------+
1 row in set (0.00 sec) session 2: mysql> insert into t1(id ,info) values(15,'a15');--hang /******************************* session 1:
mysql> select * from t1;
+-----+------+------+
| sn | id | info |
+-----+------+------+
| 235 | 1 | a1 |
| 236 | 2 | a2 |
| 237 | 3 | a3 |
| 238 | 4 | a4 |
| 239 | 5 | a5 |
| 240 | 6 | a6 |
| 241 | 7 | a7 |
| 242 | 8 | a8 |
| 243 | 9 | a9 |
| 244 | 10 | a10 |
| 245 | 15 | a15 |
+-----+------+------+
11 rows in set (0.00 sec) mysql> select * from t1 where id BETWEEN 10 and 20 for update;
+-----+------+------+
| sn | id | info |
+-----+------+------+
| 244 | 10 | a10 |
| 245 | 15 | a15 |
+-----+------+------+
2 rows in set (0.00 sec) session 2:
Database changed
mysql> insert into t1(id,info) values(15,'a15'); --hang 一个区间 可以跨越一个单独的index value,多个index value,甚至是空的。 区间锁 是在性能和并发折中的一部分,用于一些事务隔离级别而不是其他 区间锁对于那些语句 锁定行实用一个唯一索引来搜索唯一的记录是不需要的 (这个不包括这种情况 查询条件只包含了多列唯一索引的部分列,在这种情况下, 区间锁确实会发生0 比如,如果id列有一个唯一索引,下面的语句使用一个 index-record lock 对于ID=100的行 它没有关系 是否其他session 插入行 在前面的区间) /***********************************
Session 1:
mysql> select * from s100;
+-----+------+------+
| sn | id | info |
+-----+------+------+
| 227 | 1 | 1a |
| 228 | 3 | 3a |
| 229 | 6 | 6a |
| 230 | 9 | 9a |
| 231 | 12 | 12a |
| 232 | 15 | 15a |
| 233 | 18 | 18a |
+-----+------+------+
7 rows in set (0.00 sec) mysql> show index from s100;
+-------+------------+-----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment |
+-------+------------+-----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| s100 | 0 | PRIMARY | 1 | sn | A | 7 | NULL | NULL | | BTREE | | |
| s100 | 1 | s100_idx1 | 1 | id | A | 7 | NULL | NULL | YES | BTREE | | |
+-------+------------+-----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
2 rows in set (0.00 sec) mysql> show variables like '%tx_isolation%';
+---------------+-----------------+
| Variable_name | Value |
+---------------+-----------------+
| tx_isolation | REPEATABLE-READ |
+---------------+-----------------+
1 row in set (0.00 sec) mysql> update s100 set info='bbb' where id=12;
Query OK, 1 row affected (0.00 sec)
Rows matched: 1 Changed: 1 Warnings: 0 Session 2: mysql> insert into s100(id,info) select 13,'xxxxxxx'; ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction
mysql>
mysql>
mysql>
mysql> insert into s100(id,info) select 12,'xxxxxxx';
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction
mysql> insert into s100(id,info) select 14,'xxxxxxx';
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction
mysql> insert into s100(id,info) select 15,'xxxxxxx';
Query OK, 1 row affected (0.00 sec)
Records: 1 Duplicates: 0 Warnings: 0 会从12 锁到14 改成unique index 呢? Session 1:
mysql> show index from s100;
+-------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment |
+-------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| s100 | 0 | PRIMARY | 1 | sn | A | 7 | NULL | NULL | | BTREE | | |
+-------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
1 row in set (0.00 sec) mysql> create unique index s100_idx1 on s100(id);
Query OK, 0 rows affected (0.05 sec)
Records: 0 Duplicates: 0 Warnings: 0 mysql> update s100 set info='bbb' where id=12;
Query OK, 0 rows affected (0.00 sec)
Rows matched: 1 Changed: 0 Warnings: 0 mysql> show index from s100;
+-------+------------+-----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment |
+-------+------------+-----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| s100 | 0 | PRIMARY | 1 | sn | A | 8 | NULL | NULL | | BTREE | | |
| s100 | 0 | s100_idx1 | 1 | id | A | 8 | NULL | NULL | YES | BTREE | | |
+-------+------------+-----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
2 rows in set (0.00 sec) Session 2: Database changed
mysql> insert into s100(id,info) select 13,'xxxxxxx';
Query OK, 1 row affected (0.00 sec)
Records: 1 Duplicates: 0 Warnings: 0 此时正常 如果没有索引或者只是 a nonunique index, 这个语句会lock 前区间 同样值得注意的是 冲突的锁可以通过不同的事务被持有在一个区间。 比如,事务A 可以持有一个共享的区间锁(gap S-lock) 在一个区间 当事务B持有一个排他的lock 在同样的区间。 冲突的gap锁可以被允许的原因是如果一个记录是从index 被清除, 区间锁持有的记录被不同的事务必须被合并 Gap locks 在InnoDB 是纯粹的抑制,这意味着只有停止其他事务插入到区间. 它们不阻止不同的事务占据区间锁在相同的区间,因此 a gap X-lock has the same effect as a gap S-lock. Gap locking 可以被显示的禁用,这个发生在如果你改变了事务的隔离级别 到 READ COMMITTED 或者启用 innodb_locks_unsafe_for_binlog system variable 在这种情况下,gap locking 是禁用的 对于查询和index scans 只用于外键约束检查和重复键检查 Next-Key Locks
Gap 锁的更多相关文章
- Mysql加锁过程详解(7)-初步理解MySQL的gap锁
Mysql加锁过程详解(1)-基本知识 Mysql加锁过程详解(2)-关于mysql 幻读理解 Mysql加锁过程详解(3)-关于mysql 幻读理解 Mysql加锁过程详解(4)-select fo ...
- InnoDB的锁机制浅析(二)—探索InnoDB中的锁(Record锁/Gap锁/Next-key锁/插入意向锁)
Record锁/Gap锁/Next-key锁/插入意向锁 文章总共分为五个部分: InnoDB的锁机制浅析(一)-基本概念/兼容矩阵 InnoDB的锁机制浅析(二)-探索InnoDB中的锁(Recor ...
- 死锁案例 GAP 锁 没有就插入,存在就更新
https://mp.weixin.qq.com/s/2obpN57D8hyorCMnIu_YAg 死锁案例八 文 | 杨一 on 运维 转 | 来源:公众号yangyidba 一.前言 死锁其实是一 ...
- gap锁 对于unique index 和Ununique index
Session 1: mysql> select * from s100; +-----+------+------+ | sn | id | info | +-----+------+---- ...
- SQLSERVER里面RR隔离级别没有GAP锁
http://www.cnblogs.com/MYSQLZOUQI/articles/3862721.html
- Mysql加锁过程详解(8)-理解innodb的锁(record,gap,Next-Key lock)
Mysql加锁过程详解(1)-基本知识 Mysql加锁过程详解(2)-关于mysql 幻读理解 Mysql加锁过程详解(3)-关于mysql 幻读理解 Mysql加锁过程详解(4)-select fo ...
- 死锁问题分析(个人认为重点讲到了gap间隙锁,解决了我一些不明报死锁的问题)
线上某服务时不时报出如下异常(大约一天二十多次):“Deadlock found when trying to get lock;”. Oh, My God! 是死锁问题.尽管报错不多,对性能目前看来 ...
- gap间隙锁
1.什么式gap锁 (1)在索引记录之间,或者在索引之前,或者索引之后的区间上加锁,就是gap锁.比如: SELECT c1 FROM t WHERE c1 BETWEEN 10 and 20 FOR ...
- mysql事务和锁InnoDB
背景 MySQL/InnoDB的加锁分析,一直是一个比较困难的话题.我在工作过程中,经常会有同事咨询这方面的问题.同时,微博上也经常会收到MySQL锁相关的私信,让我帮助解决一些死锁的问题.本文,准备 ...
随机推荐
- jquery插件讲解:轮播(SlidesJs)+验证(Validation)
SlidesJs(轮播支持触屏)——官网(http://slidesjs.com) 1.简介 SlidesJs是基于Jquery(1.7.1+)的响应幻灯片插件.支持键盘,触摸,css3转换. 2.代 ...
- Agg vs. Cairo 二维绘图引擎之比较和选择 .
Agg vs. Cairo 二维绘图引擎之比较和选择 cheungmine 当今时代对于作为二维图形软件开发者, 是幸运的.因为除了Windows GDI/GDI+之外,我们还有很多其他的选择.而且这 ...
- codeforces 316F3 Suns and Rays
题目在此 找出中有多少个太阳以及每个太阳的散发线段. 算法 原图: 将图"缩小",如果一个白点的四周有黑点,那么把这个白点变成黑点: 将图"放大",即上述&qu ...
- uva 10313 Pay the Price(完全背包)
题目连接:10313 - Pay the Price 题目大意:有0~300这300种价值的金额. 现在可能给出参数: 1个:n, 输出可以组成价值n的方式的个数. 2个:n, a输出用个数小于a的价 ...
- 向架构师进军--->系统架构设计基础知识
假设你对项目管理.系统架构有兴趣,请加微信订阅号“softjg”,增加这个PM.架构师的大家庭 在解说系统架构设计之前,有必要补充一下架构相关的概念,因此本博文主要讲述架构.架构师和架构设计等相关的概 ...
- KMP算法原理与实现(精简)
思想:使源字符串中的下标不回溯,利用模式字符串自身的相关性,减少模式字符串中下标回溯的距离.从而减少比较的次数. 关键问题: 分析模式字符串,得出 部分匹配值数组. 原理参考此处. 具体实现: #in ...
- WCF技术剖析之二十: 服务在WCF体系中是如何被描述的?
原文:WCF技术剖析之二十: 服务在WCF体系中是如何被描述的? 任何一个程序都需要运行于一个确定的进程中,进程是一个容器,其中包含程序实例运行所需的资源.同理,一个WCF服务的监听与执行同样需要通过 ...
- USB基础简介
一.USB2.0 Universal Serial Bus (通用串行总线) 符合USB总线数据通信要求的通信协议 1.意义 1.易用(热插拔.即插即用) 2.易扩充(USBHub可同时操作127个 ...
- poj 3263 Tallest Cow
一个压了很久的题目,确实很难想,看了别人的做法后总算明白了. 首先要明白一点,因为题目说明了不会有矛盾,所以题目给出来的区间是不能相交的,否则是矛盾的.(原因自己想) 然后既然区间只能是包含的,就很明 ...
- SQL窗体函數一例
需求: MSSQL,列出服務實例中全部數據庫的例如以下信息: 數據庫ID.數據庫名.創建日期.數據文件類型.數據文件大小.數據庫總大小.文件所在路徑. 寫法(後面的百分比為所花時間占比): -- 连接 ...