锁定读(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,结构如下:

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

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

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;

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

下面这组操作也是类似:

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;

和前面的情况类似,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. 13-Verilog for Design

    Verilog for Design 设计人员知道写的RTL可以综合成么样的电路 设计人员对于硬件系统进行描述 验证人员搭建验证环境对设计人员描述的硬件系统进行验证 对Standcell,模拟/定制I ...

  2. TiDB的搭建与维护过程

    TiDB的搭建与维护过程 背景 总结一下TiDB的搭建以及简单维护过程. 目标: 简单快速的创建TiDB数据库,以及进行备份恢复等工作. TiDB 简介 TiDB(全称:Ti Distributed ...

  3. [转帖]【InfluxDB V2.0】介绍与使用,flux查询、数据可视化

    目录 一.关键概念 二.系统结构 三.配置文件 四.Flux查询语句 五.可视化数据 附录 一.关键概念 相比V1 移除了database 和 RP,增加了bucket. V2具有以下几个概念: ti ...

  4. 申威下单盘SSD与四块盘RAID5的性能测试结果

    申威下单盘SSD与四块盘RAID5的性能测试结果 背景 背景不在说了 申威服务器.. 结论 天坑 做了raid写入性能下降明显. 充分怀疑驱动不行. 四快盘的raid5 跟单盘的读几乎没区别. 感觉这 ...

  5. P9805 [POI2022~2023R1] ply

    1st思路 贪心 当遇到左括号深度加一,可如果当前深度大于 \(H\) 时深度减二,并且 \(ans\) 加一.相当于进行一次翻转操作. 当遇到右括号深度减一,当深度小于零时深度加二,并且 \(ans ...

  6. C# Switch优雅写法

    1 private static bool CanBeUpdateOrDel(bool 是否提交, bool 是否撤回, string 审核状态) => (是否提交, 是否撤回, 审核状态) s ...

  7. 提升vscode的搜索速度

    在全局搜索速度上vscode比pycharm要慢不少,尤其是对于我们这种近二十年历史的项目代码来说特别明显,所以这里记录一下我是如何加快vscode的搜索速度的. 官方的搜索建议 https://co ...

  8. springboot集成swagger之knife4j实战(升级版)

    官方文档链接:https://doc.xiaominfo.com/ 一.Knifej和swagger-bootstrap-ui对比 Knife4j在更名之前,原来的名称是叫swagger-bootst ...

  9. silce的扩容,截取,使用规范总结

    切片 什么是slice slice的创建使用 slice使用的一点规范 slice和数组的区别 slice的append是如何发生的 复制Slice和Map注意事项 接收 Slice 和 Map 作为 ...

  10. Docker中Nginx部署go应用

    docker配合Nginx部署go应用 Nginx 名词解释 正向代理 反向代理 构建镜像 Nginx镜像 配置nginx.conf server_name Nginx中的负载均衡 轮询 upstre ...