InnoDB Lock浅谈
数据库使用锁是为了支持更好的并发,提供数据的完整性和一致性。InnoDB是一个支持行锁的存储引擎,锁的类型有:共享锁(S)、排他锁(X)、意向共享(IS)、意向排他(IX)。为了提供更好的并发,InnoDB提供了非锁定读:不需要等待访问行上的锁释放,读取行的一个快照。该方法是通过InnoDB的一个特性:MVCC来实现的。
当一个事务获取了行r的共享锁,那么另外一个事务也可以立即获取行r的共享锁,因为读取并未改变行r的数据,这种情况就是锁兼容。但是如果有事务想获得行r的排它锁,则它必须等待事务释放行r上的共享锁—这种情况就是锁不兼容,二者兼容性如下表格所示:
|
排它锁和共享锁的兼容性 |
||
|
X 排它锁 |
S 共享锁 |
|
|
X 排它锁 |
冲突 |
冲突 |
|
S 共享锁 |
冲突 |
兼容 |
InnoDB锁的扩展,由于InnoDB支持的是行级别锁,所以意向锁其实不太会阻塞全表scan以下的任何请求。共享锁、排它锁、意向共享锁、意向排它锁相互之间都是有兼容/互斥关系的,它们之间的兼容关系如下表:
|
X 排它锁 |
S 共享锁 |
IX 意向排它锁 |
IS 意向共享锁 |
|
|
X 排它锁 |
冲突 |
冲突 |
冲突 |
冲突 |
|
S 共享锁 |
冲突 |
兼容 |
冲突 |
兼容 |
|
IX 意向排它锁 |
冲突 |
冲突 |
兼容 |
兼容 |
|
IS 意向共享锁 |
冲突 |
兼容 |
兼容 |
兼容 |
InnoDB有三种行锁的算法:
1,Record Lock:单个行记录上的锁。
2,Gap Lock:间隙锁,锁定一个范围,但不包括记录本身。
3,Next-Key Lock:1+2(Gap Lock+Record Lock),锁定一个范围,并且锁定记录本身。对于行的查询,都是采用该方法,主要目的是解决幻读的问题。
Record Lock 总是会去锁住索引记录,如果innodb存储引擎表在建立的时候没有设置任何一个索引,而且查询的时候没有使用到索引,那么这时就会导致表锁。
下面做下测试,这样能让大家更好理解各种锁算法:
测试一:
在session A操作:
mysql> create table t1 ( id int primary key);
Query OK, 0 rows affected (0.06 sec) mysql> insert into t1 values(1),(3),(5),(8),(11);
Query OK, 5 rows affected (0.01 sec)
Records: 5 Duplicates: 0 Warnings: 0 mysql> select * from t1;
+----+
| id |
+----+
| 1 |
| 3 |
| 5 |
| 8 |
| 11 |
+----+
5 rows in set (0.00 sec)
查看当前隔离级别:
mysql> show variables like '%iso%';
+---------------+-----------------+
| Variable_name | Value |
+---------------+-----------------+
| tx_isolation | REPEATABLE-READ |
+---------------+-----------------+
1 row in set (0.00 sec)
在A session执行相关测试操作
mysql> begin;
Query OK, 0 rows affected (0.00 sec) mysql> select * from t1 where id=8 for update;
+----+
| id |
+----+
| 8 |
+----+
1 row in set (0.03 sec)
在B session操作:
mysql> begin;
Query OK, 0 rows affected (0.00 sec) mysql> insert into t1 select 4;
Query OK, 1 row affected (0.00 sec)
Records: 1 Duplicates: 0 Warnings: 0 mysql> insert into t1 select 6;
Query OK, 1 row affected (0.00 sec)
Records: 1 Duplicates: 0 Warnings: 0 mysql> insert into t1 select 7;
Query OK, 1 row affected (0.00 sec)
Records: 1 Duplicates: 0 Warnings: 0 mysql> insert into t1 select 9;
Query OK, 1 row affected (0.00 sec)
Records: 1 Duplicates: 0 Warnings: 0
分析:InnoDB对于行的查询都是采用了Next-Key Lock的算法,锁定的不是单个值,而是一个范围,是由于id是主键且唯一,当查询的索引含有唯一属性的时候,Next-Key Lock 会进行优化,将其降级为Record Lock,即仅锁住索引本身,不是范围。所以在B会话中,插入4、6、7、9的值不会阻塞,而且成功插入,锁住记录本身,从而提高并发性。
测试2:
在A seesion 操作:
mysql> create table t2 ( id int, vid int, primary key (id), key(vid));
Query OK, 0 rows affected (0.06 sec) mysql> insert into t2 select 1,1;
Query OK, 1 row affected (0.00 sec)
Records: 1 Duplicates: 0 Warnings: 0 mysql> insert into t2 select 3,1;
Query OK, 1 row affected (0.00 sec)
Records: 1 Duplicates: 0 Warnings: 0 mysql> insert into t2 select 5,3;
Query OK, 1 row affected (0.01 sec)
Records: 1 Duplicates: 0 Warnings: 0 mysql> insert into t2 select 7,6;
Query OK, 1 row affected (0.01 sec)
Records: 1 Duplicates: 0 Warnings: 0 mysql> insert into t2 select 10,8;
Query OK, 1 row affected (0.00 sec)
Records: 1 Duplicates: 0 Warnings: 0
在t2中,vid列是辅助索引,还是在A会话执行以下操作:
mysql> begin;
Query OK, 0 rows affected (0.00 sec) mysql> select * from t2 where vid=3 for update;
+----+------+
| id | vid |
+----+------+
| 5 | 3 |
+----+------+
1 row in set (0.01 sec)
在B seesion操作(为了加快测试,先设置下):
mysql> set global innodb_lock_wait_timeout=3;
Query OK, 0 rows affected (0.00 sec) mysql> set global lock_wait_timeout=3;
Query OK, 0 rows affected (0.00 sec) mysql> show global variables like "%lock_wait_timeout%";
+--------------------------+-------+
| Variable_name | Value |
+--------------------------+-------+
| innodb_lock_wait_timeout | 3 |
| lock_wait_timeout | 3 |
+--------------------------+-------+
2 rows in set (0.00 sec)
mysql> begin;
Query OK, 0 rows affected (0.00 sec)
mysql> select * from t2 where id=5 lock in share mode;
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction
mysql> insert into t2 select 4,2;
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction
mysql> insert into t2 select 6,5;
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction
mysql> insert into t2 select 6,6;
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction
分析:这时的SQL语句通过索引列vid进行查询,因此将会使用传统的Next-Key Locking技术加锁,并且由于有两个索引,需要分别进行锁定,对于聚集索引,仅对列id等于5的索引加上Record Lock,即只锁住5这个记录,但对于辅助索引列,则会用上Next-Key Lock算法,上面索引有1,1,3,6,8,被Next-Key Locking的区间为:(-∞,1],(1,1],(1,3],(3,6],(6,8],(8,+∞),因此它会锁住范围是(1,3],特别需要注意的是,InnoDB存储引擎还会对辅助索引下一个键值加上gap lock,因为还会锁住范围(3,6]。辅助索引列实际会锁住的值有2,3,4,5,6。
在B seesion操作:
mysql>insert into t2 select 2,1;
Query OK, 1 row affected (0.00 sec)
Records: 1 Duplicates: 0 Warnings: 0
mysql> insert into t2 select 8,6;
Query OK, 1 row affected (0.00 sec)
Records: 1 Duplicates: 0 Warnings: 0
mysql> insert into t2 select 6,7;
Query OK, 1 row affected (0.00 sec)
Records: 1 Duplicates: 0 Warnings: 0
可以看到,没在锁定范围的,可以正常插入。
测试3:
在session A操作:
mysql> create table t3 ( id int, name char(20));
Query OK, 0 rows affected (0.03 sec) mysql> insert into t3 select 1,'aa';
Query OK, 1 row affected (0.00 sec)
Records: 1 Duplicates: 0 Warnings: 0 mysql> insert into t3 select 2,'bb';
Query OK, 1 row affected (0.01 sec)
Records: 1 Duplicates: 0 Warnings: 0 mysql> insert into t3 select 3,'cc';
Query OK, 1 row affected (0.01 sec)
Records: 1 Duplicates: 0 Warnings: 0 mysql> show create table t3\G
*************************** 1. row ***************************
Table: t3
Create Table: CREATE TABLE `t3` (
`id` int(11) DEFAULT NULL,
`name` char(20) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1
1 row in set (0.03 sec)
mysql> begin;
Query OK, 0 rows affected (0.00 sec)
mysql> update t3 set name='BB' where id=2;
Query OK, 1 row affected (0.00 sec)
Rows matched: 1 Changed: 1 Warnings: 0
在B session操作:
mysql> begin;
Query OK, 0 rows affected (0.03 sec) mysql> update t3 set name='CC' where id=3;
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction
mysql> update t3 set name='AA' where id=1;
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction
分析:可以看出,只有通过索引检索数据,innodb才会采用行锁,否则,innodb将会使用表锁。生产环境一定要注意。
测试四:
在A seesion操作:
mysql> create table t4 ( id int , uid int, unique key(id,uid))engine=innodb;
Query OK, 0 rows affected (0.05 sec) mysql> insert into t4 select 1,2;
Query OK, 1 row affected (0.00 sec)
Records: 1 Duplicates: 0 Warnings: 0 mysql> insert into t4 select 1,3;
Query OK, 1 row affected (0.01 sec)
Records: 1 Duplicates: 0 Warnings: 0 mysql> insert into t4 select 1,5;
Query OK, 1 row affected (0.00 sec)
Records: 1 Duplicates: 0 Warnings: 0 mysql> insert into t4 select 1,8;
Query OK, 1 row affected (0.00 sec)
Records: 1 Duplicates: 0 Warnings: 0
表t4创建了一个唯一索引。
mysql> begin;
Query OK, 0 rows affected (0.00 sec) mysql> select * from t4 where uid=5 for update;
+------+------+
| id | uid |
+------+------+
| 1 | 5 |
+------+------+
1 row in set (0.00 sec)
在B session操作:
mysql> begin;
Query OK, 0 rows affected (0.03 sec)
mysql> insert into t4 select 1,1;
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction
mysql> insert into t4 select 1,4;
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction
mysql> insert into t4 select 1,7;
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction
mysql>
解释:可见依然采用的是Next-Key Lock进行锁定的
总结:
1、对于Next-key Lock算法,锁定的是范围,包含记录本身,对辅助索引下一个键值加上Gap Lock
2、对于唯一索引,其加上的是Record Lock,仅锁住记录本身。但也有特别情况,那就是唯一索引由多个列组成,而查询仅是查找多个唯一索引列中的其中一个,那么加锁的情况依然是Next-key Lock。
3、innodb存储引擎是通过给索引上的索引项加锁来实现,这意味着:只有通过索引条件检索数据,innodb才会使用行锁,否则,innodb将使用表锁
参考资料
大牛何登成的博客:http://hedengcheng.com/?p=771
<<MySQL技术内幕--InnoDB存储引擎第2版>>
InnoDB Lock浅谈的更多相关文章
- Innodb锁机制:Next-Key Lock 浅谈
数据库使用锁是为了支持更好的并发,提供数据的完整性和一致性.InnoDB是一个支持行锁的存储引擎,锁的类型有:共享锁(S).排他锁(X).意向共享(IS).意向排他(IX).为了提供更好的并发,Inn ...
- Innodb锁机制:Next-Key Lock 浅谈(转)
http://www.cnblogs.com/zhoujinyi/p/3435982.html 数据库使用锁是为了支持更好的并发,提供数据的完整性和一致性.InnoDB是一个支持行锁的存储引擎,锁的类 ...
- 浅谈mysql innodb缓存策略
浅谈mysql innodb缓存策略: The InnoDB Buffer Pool Innodb 持有一个存储区域叫做buffer pool是为了在内存中缓存数据和索引,知道innodb buffe ...
- 浅谈MySQL存储引擎-InnoDB&MyISAM
存储引擎在MySQL的逻辑架构中位于第三层,负责MySQL中的数据的存储和提取.MySQL存储引擎有很多,不同的存储引擎保存数据和索引的方式是不同的.每一种存储引擎都有它的优势和劣势,本文只讨论最常见 ...
- MYSQL优化浅谈,工具及优化点介绍,mysqldumpslow,pt-query-digest,explain等
MYSQL优化浅谈 msyql是开发常用的关系型数据库,快速.稳定.开源等优点就不说了. 个人认为,项目上线,标志着一个项目真正的开始.从运维,到反馈,到再分析,再版本迭代,再优化… 这是一个漫长且考 ...
- 重新学习MySQL数据库6:浅谈MySQL的中事务与锁
『浅入深出』MySQL 中事务的实现 在关系型数据库中,事务的重要性不言而喻,只要对数据库稍有了解的人都知道事务具有 ACID 四个基本属性,而我们不知道的可能就是数据库是如何实现这四个属性的:在这篇 ...
- 浅谈Mysql共享锁、排他锁、悲观锁、乐观锁及其使用场景
浅谈Mysql共享锁.排他锁.悲观锁.乐观锁及其使用场景 Mysql共享锁.排他锁.悲观锁.乐观锁及其使用场景 一.相关名词 |--表级锁(锁定整个表) |--页级锁(锁定一页) |--行级锁(锁 ...
- 浅谈B+树索引的分裂优化(转)
http://www.tamabc.com/article/85038.html 从MySQL Bug#67718浅谈B+树索引的分裂优化 原文链接:http://hedengcheng.com/ ...
- 浅谈SQL Server 对于内存的管理
简介 理解SQL Server对于内存的管理是对于SQL Server问题处理和性能调优的基本,本篇文章讲述SQL Server对于内存管理的内存原理. 二级存储(secondary storage) ...
随机推荐
- 从0到1搭建基于Kafka、Flume和Hive的海量数据分析系统(一)数据收集应用
大数据时代,一大技术特征是对海量数据采集.存储和分析的多组件解决方案.而其中对来自于传感器.APP的SDK和各类互联网应用的原生日志数据的采集存储则是基本中的基本.本系列文章将从0到1,概述一下搭建基 ...
- images & Skeleton
images & Skeleton image placeholder & loading ... skeleton.css https://github.com/dhg/Skelet ...
- HGOI20180815 (NOIP 提高组模拟赛 day2)
Day 2 rank 11 100+35+30=165 本题是一道数论题,求ax+by=c的正整数对(x,y) x>=0并且y>=0 先说下gcd: 求a,b公约数gcd(a,b) 如gc ...
- 洛谷 P2051 [AHOI2009]中国象棋 解题报告
P2051 [AHOI2009]中国象棋 题目描述 这次小可可想解决的难题和中国象棋有关,在一个N行M列的棋盘上,让你放若干个炮(可以是0个),使得没有一个炮可以攻击到另一个炮,请问有多少种放置方法. ...
- 洛谷 P1309 瑞士轮 解题报告
P1309 瑞士轮 题目背景 在双人对决的竞技性比赛,如乒乓球.羽毛球.国际象棋中,最常见的赛制是淘汰赛和循环赛.前者的特点是比赛场数少,每场都紧张刺激,但偶然性较高.后者的特点是较为公平,偶然性较低 ...
- Go 语言中的方法,接口和嵌入类型
https://studygolang.com/articles/1113 概述 在 Go 语言中,如果一个结构体和一个嵌入字段同时实现了相同的接口会发生什么呢?我们猜一下,可能有两个问题: 编译器会 ...
- 基于CMS的组件复用实践
目前前端项目大多基于Vue.React.Angular等框架来实现,这一类框架都有一个明显的特点:基于模块化以及组件化思维.所以,开发者在使用上述框架时,实际上是在写一个一个的组件,并且组件与组件之间 ...
- 关于Thinkphp5类命名导致的“模块不存在”问题
不得不说,thinkphp5就是个十足的坑货, 在thinkphp3.2.3的基础上,函数.用法变了也就忍了, 在mac下写的一个类文件 GetRedisData.php,在mac+mamp环境下是正 ...
- Scala进阶之路-Scala函数篇详解
Scala进阶之路-Scala函数篇详解 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.传值调用和传名调用 /* @author :yinzhengjie Blog:http: ...
- Java基础-编写问候语-“Hello World”
Java基础-编写问候语-“Hello World” 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.编写“Hello World”程序 1>.编写源代码 任何文本编辑起都 ...