【译文】InnoDB 的不同的SQL如何加锁
http://dev.mysql.com/doc/refman/5.6/en/innodb-locks-set.html
前置:检索如果用不到索引,会扫描全表,并根据策略加锁。所以,这就是我们合理建立索引的缘由。
锁定读、Update、Delete,在处理sql过程中, 一般会在每条扫描过的索引记录上设置记录锁。语句中是否有where条件并没有关系(会排除)。InnoDB不会记住实际上的Where条件,但他知道被扫描过的索引范围。使用的锁通常是next-key锁,也会锁住记录之前的“gap”。Next-Key锁不仅仅锁住扫描到的合法索引记录,同时会阻塞插入gap间隙中,gap是指上一条合法索引记录到当前扫描到的合法索引记录的开区间。gap锁可以被显示的禁止,导致next-key不会被使用。
事物的隔离级别同样会影响使用什么锁。
如果一个二级索引被用来扫描,且索引记录(二级索引,非唯一索引)将要加排他锁,InnoDB会检索相对应的聚簇索引记录,并锁住。
聚簇索引(clustered index)
1) 有主键时,根据主键创建聚簇索引
2) 没有主键时,会用一个唯一且不为空的索引列做为主键,成为此表的聚簇索引
3) 如果以上两个都不满足那innodb自己创建一个虚拟的聚集索引
辅助索引(secondary index)
非聚簇索引都是辅助索引,像复合索引、前缀索引、唯一索引
如果没有合适的索引使用,MySQL会扫面整张表,来处理语句,这样表中的每一行都会被锁住(合理建立索引,提高并发效率)。
对于 SELECT ... FOR UPDATE
or SELECT ... LOCK IN SHARE MODE,扫描到的行都会锁住,并且期望在有些row不会加入结果集中(例如不满足Where条件)释放这些行的锁。注:其实扫描了全表,只不过在扫描完成之后,判断Where条件时不满足,则会释放锁。
然而对于某些情况下,不会立即释放行锁,因为在查询执行期间一个结果行和他的原始来源之间的关系可能已经丢失,例如Union,从表中扫描行,在计算他们是否加入结果集之前,这些行可能被插入临时表中。此时,临时表中的行和原始表中的行的关系已经丢失,原始表中的行不会解锁知道查询执行完成。
InnoDB按照如下设置具体的锁:
SELECT ... FROM 是一个一致性非锁定读,读取数据库的快照,不会加锁,除非隔离级别为S。对于S隔离级别,检索结果集在索引记录项上使用共享锁且是next-key锁。但是,当唯一确定记录时,next-key锁会降级为记录锁。
SELECT ... FROM ... LOCK IN SHARE MODE 在检索到的所有索引记录上设置共享锁且是next-key锁。但是,当唯一确定记录时,next-key锁会降级为记录锁。
SELECT ... FROM ... FOR UPDATE
在检索到的每条记录上的每一个记录上加排他锁且是next-key锁。但是,当唯一确定记录时,next-key锁会降级为记录锁。对索引记录加的排他锁阻塞共享锁和某些隔离级别的操作读。一致性非锁定读,会忽略任何锁。UPDATE ... WHERE ...
在检索到的每条记录上的每一个记录上加排他锁且是next-key锁。但是,当唯一确定记录时,next-key锁会降级为记录锁。- 当Update修改一个聚簇索引记录,隐式的锁会加在受影响的(将要更新的字段)的二级索引记录(不是全部索引记录,Where字段指定范围)上。Update操作同样会加共享锁在受影响的二级索引记录上,当在插入一个新的二级索引记录之前执行重复检查时,或者当插入一个新的二级索引记录时。
DELETE FROM ... WHERE ... 在检索到的每条记录上的每一个记录上加排他锁且是next-key锁。但是,当唯一确定记录时,next-key锁会降级为记录锁。
INSERT 设置一个排它锁在插入的行上,这是一个记录锁,不是next-key,就是说没有gap锁,不会阻止其他事物插入被插记录之前的gap中。
在插入之前,一种叫插入意向锁的gap类型锁,被设置,这个锁表示对事物插入同一个gap中时,不需要相互等待,只要他们不是插入gap中相同的位置。
设置插入操作的排他锁之前,现货去gap的插入意向锁,俩个事物可以在同一个gap(重叠也可以)加插入意向锁不会阻塞。
如果有重复冲突,一个共享锁在重复的索引记录上设置。共享锁的使用可能导致死锁:当多个会话插入相同的行时,如果有某个会话已经持有了X锁,此时会导致死锁。举个例子:如果有某个会话删除该行,另外俩个插入行,则会死锁。
Session 1:
START TRANSACTION;
INSERT INTO t1 VALUES(1);Session 2:
START TRANSACTION;
INSERT INTO t1 VALUES(1);Session 3:
START TRANSACTION;
INSERT INTO t1 VALUES(1);Session 1:
ROLLBACK;
上述情况是会话1已经获取了x锁在r行上,会话2和4都会引起重复键冲突,俩个会话都转而去请求r行共享锁,当会话1回滚时,它释放他的排它锁,会话2和3的共享锁请求被授予,此时,会话2和3死锁:没有任何一个会获取排它锁,因为他们都持有了共享锁。
Session 1:
START TRANSACTION;
DELETE FROM t1 WHERE i = 1;Session 2:
START TRANSACTION;
INSERT INTO t1 VALUES(1);Session 3:
START TRANSACTION;
INSERT INTO t1 VALUES(1);Session 1:
COMMIT;
上述情况和第一种类似。
INSERT ... ON DUPLICATE KEY UPDATE 不同与简单的Insert,当重复值冲突时,加的锁是一个排它next-key锁而不是一个共享锁-记录锁。
REPLACE 如果在唯一key上没有冲突,像INSERT一样加锁。够则像INSERT ... ON DUPLICATE KEY UPDATE一样
- INSERT INTO T SELECT ... FROM S WHERE ... 在插入T表中的每一行上加一个排它记录锁,注意没有gap。如果事物级别是RC,或者启用了
innodb_locks_unsafe_for_binlog
(此时不能是隔离级别S),InnoDB在S表上是一致性非锁定读(不加锁)。否则,InnoDB会设置共享的next-key锁到从S表检索结果中的行。
CREATE TABLE ... SELECT ...
执行 SELECT使用共享的next-key锁,或者一致性非锁定读,就像
INSERT ... SELECT
.一样.
当一个SELECT在类似REPLACE INTO t SELECT ... FROM s WHERE ...
or UPDATE t ... WHERE col IN (SELECT ... FROM s ...)的结果中,InnoDB设置共享且next-key锁在表S上的行上。
- 当初始化表中先前指定的AUTO_COMMIT列时,InnoDB设置一把排它锁在与AUTO_COMMIT列相关的索引的尾部,在访问自动增长计数器时,InnoDB使用的是特殊的AUTO-INC表级锁模式,该锁在语句执行完成之后释放,而不是在事物结束的时候释放,所以性能也不是太糟。InnoDB获取先前已经初始化的AUTO_COMMIT列时,不需要加任何的锁。
- 如果一个外键约束定义在表中,任何要求约束检查的插入、更新和删除设置一把共享行锁到到特定的外键记录上,以便检查约束。
LOCK TABLES 设置表级锁
【译文】InnoDB 的不同的SQL如何加锁的更多相关文章
- MySQL innodb中各种SQL语句加锁分析
概要 Locking read( SELECT ... FOR UPDATE or SELECT ... LOCK IN SHARE MODE),UPDATE以及DELETE语句通常会在他扫描的索引所 ...
- InnoDB的锁机制浅析(四)—不同SQL的加锁状况
不同SQL的加锁状况 文章总共分为五个部分: InnoDB的锁机制浅析(一)-基本概念/兼容矩阵 InnoDB的锁机制浅析(二)-探索InnoDB中的锁(Record锁/Gap锁/Next-key锁/ ...
- 查看sql语句加锁信息
问题: 最近使用quartz集群,总是报deadlock问题,所以需要查看一下执行的sql导致的加锁冲突. 步骤: 1.在要测试的库中创建指定表innodb_lock_monitor create t ...
- MySQL中一条SQL的加锁分析
MySQL中一条SQL的加锁分析 id主键 + RC id唯一索引 + RC id非唯一索引 + RC id无索引 + RC id主键 + RR id唯一索引 + RR id非唯一索引 + RR id ...
- SQL语句加锁分析
背景 MySQL中SQL加锁的情况十分复杂,不同隔离级别.不同索引类型.索引是否命中的SQL加锁各不相同. 然而在分析死锁过程当中,熟知各种情况的SQL加锁是分析死锁的关键,因此需要将MySQL的各种 ...
- InnoDB的行锁模式及加锁方法
MYSQL:InnoDB的行锁模式及加锁方法 共享锁:允许一个事务度一行,阻止其他事务获取相同数据集的排他锁. SELECT * FROM table_name WHERE ... LOCK IN S ...
- 关于InnoDB的读写锁类型以及加锁方式
(本文为了方便,英文关键词都都采用小写方式,相关知识点会简单介绍,争取做到可以独立阅读) 文章开始我会先介绍本文需要的知识点如下: innodb的聚簇索引(聚集索引)和非聚簇索引(二级索引.非聚集索引 ...
- 何登成大神对Innodb加锁的分析
背景 MySQL/InnoDB的加锁分析,一直是一个比较困难的话题.我在工作过程中,经常会有同事咨询这方面的问题.同时,微博上也经常会收到MySQL锁相关的私信,让我帮助解决一些死锁的问题.本文,准备 ...
- 解决死锁之路3 - 常见 SQL 语句的加锁分析 (转)
出处:https://www.aneasystone.com/archives/2017/12/solving-dead-locks-three.html 这篇博客将对一些常见的 SQL 语句进行加锁 ...
随机推荐
- [转]数据库中Schema(模式)概念的理解
在学习数据库时,会遇到一个让人迷糊的Schema的概念.实际上,schema就是数据库对象的集合,这个集合包含了各种对象如:表.视图.存储过程.索引等. 如果把database看作是一个仓库,仓库很多 ...
- C# 委托、匿名方法、扩展方法
一.委托的使用: 详细委托和事件解释请看另一篇:http://www.cnblogs.com/Liyuting/p/6760706.html 二.匿名方法 三.扩展方法
- [android] 手机卫士来电显示号码归属地
继续N天前的项目 开启服务监听手机来电,查询数据库,显示归属地 详细内容可以参考这篇博文:http://www.cnblogs.com/taoshihan/p/5331232.html Address ...
- xcode 调试器 LLDB
本文完全转载,转载地址:点击这里 你是否曾经苦恼于理解你的代码,而去尝试打印一个变量的值? NSLog(@"%@", whatIsInsideThisThing); 或者跳过一个函 ...
- java 数据脱敏
所谓数据脱敏是指对某些敏感信息通过脱敏规则进行数据的变形,实现敏感隐私数据的可靠保护.在涉及客户安全数据或者一些商业性敏感数据的情况下,在不违反系统规则条件下,对真实数据进行改造并提供测试使用,如身份 ...
- 如何优雅的爬取 gzip 格式的页面并保存在本地(java实现)
1. 引言 在爬取汽车销量数据时需要爬取 html 保存在本地后再做分析,由于一些页面的 gzip 编码格式, 获取后要先解压缩,否则看到的是一片乱码.在网络上仔细搜索了下,终于在这里找到了一个优雅的 ...
- 用数组指针遍历数组,FOR/FOREACH遍历数组
1. 用数组指针遍历一维数组 <?php header("Content-type:text/html;charset=utf-8"); /*用数组指针遍历一位数组的值*/ ...
- springJDBC 中JdbcTemplate 类方法使用
一,Dao IUserinfDao package com.dkt.dao; import java.util.List; import com.dkt.entity.Userinfo; public ...
- CSS 媒体查询创建响应式网站
使用 CSS 媒体查询创建响应式网站 适用于所有屏幕大小的设计 固定宽度的静态网站很快被灵活的响应式设计所取代,该设计可以根据屏幕大小进行上扩和下扩.利用响应式设计,无论您采用什么设备或屏幕来访问网 ...
- 在GDI+中如何实现以左下角为原点的笛卡尔坐标系
今天写了一个求点集合的凸包的一个算法,虽然结果求解出来了,但是想将过程用GDI+绘制出来,就需要将点绘制出来,然而c#GDI+中绘图的坐标与我们常用数学中笛卡尔坐标系是不一样的,所以就要转换GDI+中 ...