锁定读(locking read)、更新(UPDATE)或删除(DELETE)通常会在SQL语句处理过程中扫描的每个索引记录上设置记录锁。语句中是否存在排除行的WHERE条件并不重要。InnoDB不记得确切的WHERE条件,而只知道哪个索引范围被扫描。这些锁通常是next-key锁,它还会阻止在记录之前插入“间隙”。然而,间隙锁(gap lock)可以被显式禁用,这会导致不使用next-key锁。

如果在检索中使用了二级索引,并且要设置的索引记录锁是排它的,则InnoDB也会检索相应的聚集索引记录并在它们上设置锁。

执行SQL语句时,如果没有找到可用的索引,MySQL必须扫描整个表来处理该语句,这样的话表的每一行都会被锁定,从而阻塞其他用户对表的所有插入。因此,创建良好的索引非常重要,这样可以避免扫描许多不必要的行。

InnoDB设置特定类型的锁,如下所示:

  • SELECT ... FROM 是一致读,读取数据库快照,除非将事务隔离级别设置为SERIALIZABLE,否则不设置锁。对于SERIALIZABLE级别,检索会在遇到的索引记录上设置共享的next-key锁。但是,对于使用唯一索引来搜索唯一行的语句,只需要一个索引记录锁。

  • 对于 SELECT ... FOR UPDATE 或者 SELECT ... LOCK IN SHARE MODE ,对扫描的行加锁,并对不符合结果集中包含条件的行(例如,如果它们不满足WHERE子句中给出的条件)释放锁。

  • SELECT ... LOCK IN SHARE MODE 在所有遇到的索引记录上设置共享的next-key锁。但是,对于使用唯一索引来搜索唯一行的语句,只需要一个索引记录锁。

  • SELECT ... FOR UPDATE 在搜索遇到的每个记录上设置排它的next-key锁。但是,对于使用唯一索引来搜索唯一行的语句,仅需要索引记录锁定。

  • UPDATE ... WHERE ... 在搜索遇到的每个记录上设置排它的next-key锁。但是,对于使用唯一索引来搜索唯一行的语句,仅需要索引记录锁定。

  • DELETE FROM ... WHERE ... 在搜索遇到的每个记录上设置排它的next-key锁。但是,对于使用唯一索引来搜索唯一行的语句,仅需要索引记录锁定。

  • INSERT 在插入的行上设置排他锁。该锁是索引记录锁,不是next-key锁(即没有间隙锁),并且不会阻止其他会话插入到插入行之前的间隙中。

举个例子,假设有一张表t1,结构如下:

  1. CREATE TABLE t1 (i INT, PRIMARY KEY (i)) ENGINE = InnoDB;

再假设,有三个会话操作顺序如下:

Session 1:

  1. START TRANSACTION;
  2. INSERT INTO t1 VALUES(1);

Session 2:

  1. START TRANSACTION;
  2. INSERT INTO t1 VALUES(1);

Session 3:

  1. START TRANSACTION;
  2. INSERT INTO t1 VALUES(1);

Session 1:

  1. ROLLBACK;

首先Session1获得i=1这一行的排它锁,接下来Session2和Session3由于主键重复只能请求获取该行的共享锁,由于行上已经有排它锁,因此Session2和Session3请求的共享锁不能被立即授予。再接着,Session1回滚,行上的排它锁被释放,于是Session2和Session3在该行上都持有共享锁,此时,死锁发生了,由于对方持有的共享锁,任何一方都不能获得该行的排它锁。

下面这组操作也是类似:

Session 1:

  1. START TRANSACTION;
  2. DELETE FROM t1 WHERE i = 1;

Session 2:

  1. START TRANSACTION;
  2. INSERT INTO t1 VALUES(1);

Session 3:

  1. START TRANSACTION;
  2. INSERT INTO t1 VALUES(1);

Session 1:

  1. COMMIT;

和前面的情况类似,Session1提交以后,Session2和Session3请求该行上的共享锁被立即授予,此时它们再请求获取排它锁时就出现死锁了,因为共享锁被另一个事务持有。

补充: 聚集索引与辅助索引

clustered index (译:聚集索引、聚簇索引)

secondary index (译:二级索引、辅助索引)

每个InnoDB表都有一个特殊的索引,称为聚集索引,用于存储行数据。通常,聚集索引与主键是同义词。为了从查询、插入和其他数据库操作中获得最佳性能,必须了解InnoDB如何使用聚集索引来优化每个表的最常见的查找和DML操作。

Typically, the clustered index is synonymous with the primary key.

通常,“clustered index” 和 “primary key” 是一个意思。

  • 当你在表上定义一个PRIMARY KEY时,InnoDB将它用作聚集索引。为创建的每个表定义一个主键。如果没有逻辑唯一的非空列或列集,请添加一个新的自动递增(auto-increment)列,其值将自动填充。

  • 如果你没有为你的表定义一个PRIMARY KEY,则MySQL会在所有键列都不为NULL的情况下找到第一个唯一索引,并且InnoDB使用它作为聚集索引。

  • 如果表没有主键或合适的唯一索引,InnoDB会在包含行ID值的合成列上内部生成一个名为GEN_CLUST_INDEX的隐藏聚集索引

通过聚集索引访问行非常快,因为索引搜索直接指向包含所有行数据的页。如果表很大,聚集索引体系结构通常节省磁盘I/O操作。

除了聚集索引之外的所有索引都称为二级索引。在InnoDB中,二级索引中的每条记录都包含该行的主键列,以及为二级索引指定的列。InnoDB使用此主键值在聚集索引中搜索行。

如果主键很长,则辅助索引将使用更多空间,因此具有主键较短是比较有利的。

With the exception of spatial indexes, InnoDB indexes are B-tree data structures. Index records are stored in the leaf pages of their B-tree or R-tree data structure. The default size of an index page is 16KB. Supported sizes are 64KB, 32KB, 16KB (default), 8KB, and 4KB.

InnoDB中不同SQL语句设置的锁的更多相关文章

  1. InnoDB 中不同SQL语句设置的锁

    锁定读.UPDATE 或 DELETE 通常会给在SQL语句处理过程扫描到的每个索引记录上设置记录锁.语句中是否存在排除该行的WHERE条件并不重要.InnoDB不记得确切的WHERE条件,但只知道哪 ...

  2. MySQL innodb中各种SQL语句加锁分析

    概要 Locking read( SELECT ... FOR UPDATE or SELECT ... LOCK IN SHARE MODE),UPDATE以及DELETE语句通常会在他扫描的索引所 ...

  3. 14.3.3 Locks Set by Different SQL Statements in InnoDB 不同的SQL语句在InnoDB里的锁设置

    14.3.3 Locks Set by Different SQL Statements in InnoDB 不同的SQL语句在InnoDB里的锁设置 locking read, 一个UPDATE,或 ...

  4. 在phpmyadmin中执行sql语句出现的错误:Unknown storage engine 'InnoDB'

    在phpmyadmin中执行sql语句出现的错误:Unknown storage engine 'InnoDB' 解决方法:解决方法:             1.关闭MySQL数据库       2 ...

  5. 重新学习MySQL数据库9:Innodb中的事务隔离级别和锁的关系

    重新学习MySQL数据库9:Innodb中的事务隔离级别和锁的关系 Innodb中的事务隔离级别和锁的关系 前言: 我们都知道事务的几种性质,数据库为了维护这些性质,尤其是一致性和隔离性,一般使用加锁 ...

  6. 【转载】Innodb中的事务隔离级别和锁的关系

    前言 我们都知道事务的几种性质,数据库为了维护这些性质,尤其是一致性和隔离性,一般使用加锁这种方式.同时数据库又是个高并发的应用,同一时间会有大量的并发访问,如果加锁过度,会极大的降低并发处理能力.所 ...

  7. 在mybatis中写sql语句的一些体会

    本文会使用一个案例,就mybatis的一些基础语法进行讲解.案例中使用到的数据库表和对象如下: article表:这个表存放的是文章的基础信息 -- ------------------------- ...

  8. [转]在EntityFramework6中执行SQL语句

    本文转自:http://www.cnblogs.com/wujingtao/p/5412329.html 在上一节中我介绍了如何使用EF6对数据库实现CRDU以及事务,我们没有写一句SQL就完成了所有 ...

  9. 在EntityFramework6中执行SQL语句

    在EntityFramework6中执行SQL语句 在上一节中我介绍了如何使用EF6对数据库实现CRDU以及事务,我们没有写一句SQL就完成了所有操作.这一节我来介绍一下如何使用在EF6中执行SQL语 ...

  10. C语言中嵌入式SQL语句

    原文:[转载]C语言中嵌入式SQL语句 http://blog.csdn.net/cnlht/archive/2007/12/12/1930960.aspx原文地址 实验内容: 掌握SQL Serve ...

随机推荐

  1. Python追踪内存占用

    技术背景 当我们需要对python代码所占用的内存进行管理时,首先就需要有一个工具可以对当前的内存占用情况进行一个追踪.虽然在Top界面或者一些异步的工具中也能够看到实时的内存变化,还有一些工具可以统 ...

  2. 你老了,别搞IT了……

    你老了,别搞IT了-- [来源]

  3. [转帖]Centos使用chrony做时间同步

    https://www.cnblogs.com/lizhaoxian/p/11260041.html Chrony是一个开源的自由软件,在RHEL 7操作系统,已经是默认服务,默认配置文件在 /etc ...

  4. [转帖]VMware Converter (P2V迁移)问题汇总

    https://www.dinghui.org/vmware-converter-p2v.html VMware vCenter Converter Standalone,是一种用于将虚拟机和物理机转 ...

  5. [转帖]enq: TX - row lock contention故障处理一则

    https://www.cnblogs.com/zhchoutai/p/7088826.html   一个非常easy的问题,之所以让我对这个问题进行总结.一是由于没我想象的简单,在处理的过程中遇到了 ...

  6. [转帖]天行健,国产CPU当自强不息

      https://baijiahao.baidu.com/s?id=1699201892754975586 本页面的文字和图像允许在CC-BY-SA 3.0协议四和GNU自由文档许可证下修改和再使用 ...

  7. [转帖]高并发系统中的尾延迟Tail Latency

    开发和运维高并发系统的工程师可能都有过类似经验,明明系统已经调优完毕,该异步的异步,该减少互斥的地方引入无锁,该减少IO的地方更换引擎或者硬件,该调节内核的调节相应参数,然而,如果在系统中引入实时监控 ...

  8. 【dp,建模】AGC032D Rotation Sort

    Problem Link 有一个长为 \(n\) 的排列 \(p\),给定 \(A,B\),你每次可以做以下两种操作之一: 选取 \(l,r\),将 \(p[l:r]\) 循环右移,代价为 \(A\) ...

  9. vue3中markRaw的使用

    markRaw 作用:将一个对象标记为不可以被转化为代理对象.返回该对象本身. 应用场景: 1.有些值不应被设置成响应式时,例如复杂的第三方类库等 2.当渲染具有不可变数据源的大列表时,跳过响应式转换 ...

  10. echarts轮训展示某个

    //学校资产占比的配置 function schollAssets() { var myChart = window.$echarts.init( document.getElementById('s ...