MySQL-InnoDB锁

innoDB中支持下面的几种锁:

  • Shared and Exclusive Locks(共享锁和独占锁)
  • Intention Locks(意向锁)
  • Record Locks(记录锁)
  • Gap Locks(间隙锁)
  • Next-Key Locks
  • Insert Intention Locks(插入意向锁)
  • AUTO-INC Locks(自动提交锁)
  • Predicate Locks for Spatial Indexes(空间索引的谓词判断锁)

Shared and Exclusive Locks(共享锁和独占锁)

这两个锁的作为范围是行级别,共享(share锁,也叫做s锁)允许持有锁的事务读取一行,允许多个事务同时获取一把share(s)锁。独占锁(Exclusive锁,也叫做x锁)允许持有锁的事务更新或者删除一行,独占锁和共享锁是互斥的,并且独占锁不支持多个事务同时获取一把锁。例子如下:

如果T1事务在一行上已经持有了r锁,这时有一个事务T2想要获取这一行数据的锁:

Intention Locks(意向锁)

他是一种表级锁。它表示,当前有事务正在获取表中行级别的锁。获取锁的顺序是,先获取意向锁(表级锁)在或者行级别锁。意向锁也有两种类型

表示事务打算在表中的单个行上设置共享锁。

表示事务打算对表中的单个行设置独占锁。

比如select ... from ... lock in share mode 获取IS lock,select ... from ... for update获取IX锁。

IS和IX对应的就是独占锁和共享锁在表级别的锁,在获取X锁之前要写获取IX锁,同样的,在获取S锁之前要先获取IS锁。IS,IX,X,S锁的关系如下:

T1/T2 X IX S IS
X Conflict Conflict Conflict Conflict
IX Conflict Compatible Conflict Compatible
S Conflict Conflict Compatible Compatible
IS Conflict Compatible Compatible Compatible

这个表格的意思如下:行代码事务T1,列代表事务T2。

T1先获取X锁,T2获取X锁,结果为Conflict(互斥)。T1先获取IS锁,T2获取IS锁,是可以获取到的。

一般来说,意向锁是不会堵塞任何,除非有显示的锁表的语句比如lock tables ... write,意向锁主要的目的是为了表示某个事务正在锁定表中的一行。通过show engine innoDB status来看,类似如下:

TABLE LOCK table `test`.`t` trx id 10080 lock mode IX

比如说,现在要修改一个表结构,有两个事务,一个要改表结构(T1),一个要做查询操作(T2),那T1怎么知道这个表中有没有行锁?全部遍历一遍所有的行?那怎么保证在遍历的时候会不会有别的事务也在获取锁呢?有了意向锁,看一下就知道了。

Record Locks(记录锁)

记录锁就是索引上的锁,记录锁的作用范围就是索引,innoDB中的锁基本都是记录锁,所以主键字段一定是有记录锁的,要是没有主键字段,Mysql就会默认增加Row_id来作为隐藏的主键字段。

比如select * from t_student where age = 12 for update,t_student 表中age是索引,这个语句就是锁住了这一行,阻止任何事务对这条数据的修改,更新,插入。用show engine innoDB status来看,如下:

------------

TRANSACTIONS

------------

Trx id counter 30386

Purge done for trx’s n:o < 30383 undo n:o < 0 state: running but idle

History list length 0

LIST OF TRANSACTIONS FOR EACH SESSION:

—TRANSACTION 421797202743296, not started

0 lock struct(s), heap size 1128, 0 row lock(s)

—TRANSACTION 421797202741680, not started

0 lock struct(s), heap size 1128, 0 row lock(s)

—TRANSACTION 421797202740872, not started

0 lock struct(s), heap size 1128, 0 row lock(s)

—TRANSACTION 30385, ACTIVE 5 sec inserting

mysql tables in use 1, locked 1

LOCK WAIT 2 lock struct(s), heap size 1128, 1 row lock(s), undo log entries 1

MySQL thread id 1029, OS thread handle 140321211012864, query id 38645 xxxx root update

/* ApplicationName=DataGrip 2021.2.2 */ insert into t_student(name, age) VALUES

(‘小粉’,12)

------- TRX HAS BEEN WAITING 5 SEC FOR THIS LOCK TO BE GRANTED:

RECORD LOCKS space id 1056 page no 5 n bits 80 index idx_student_age of table data.t_student trx id 30385 lock_mode X locks gap before rec insert intention waiting

Record lock, heap no 3 PHYSICAL RECORD: n_fields 2; compact format; info bits 0

0: len 4; hex 8000000d; asc ;;

1: len 4; hex 80000002; asc ;;

Gap Locks(间隙锁)

gap锁是索引之间的锁,他是一个范围锁。比如select * from t_student where age > 12 and age < 14 for update,范围锁,锁的是12到14之间的index,它会阻止在这个区间里面的插入不管数据是否存在,比如插入age为13的数据,13在这个区间,不管13是否真的存在。因为现在存在的这些记录之间的范围已经被锁住了

Gap可能会跨越单个索引值,多个索引值,或者可能为空,比如:

select *
from t_student where (age > 12 and score > 0) and (age<15 and  score < 5);
-- age和score都加了索引

gap锁也有两种类型

  • shared gap lock(共享gap锁,也叫做gap S-lock)。

  • exclusive gap lock(排他gap锁,也叫做gap X-lock)。

    gap锁的目的只是为了阻止区间插入,gap锁是可以共存的,两个事务可以同时获取同一个区间的gap锁。共享和排他的gap锁没有区别,它们之间没有冲突,并且执行同样的功能。

现在来看删除和更新的情况

表结构如下:

-- auto-generated definition
create table t_student
(id    int auto_incrementprimary key,name  varchar(200)     null,age   int              null,score double default 0 not null comment '分数'
);create index idx_scoreon t_student (score);create index idx_student_ageon t_student (age);
  • 删除

    • 删除存在的数据

删除存在的数据,会堵塞。gap锁锁住现存的记录之间的范围。因为13存在。
  • 删除不存在的数据

不会堵塞,gap锁会锁住现存的记录之间的范围,13已经被删除了。
  • 更新操作和上面的结果一样。

要知道,gap锁只是在RR隔离级别下才会用得到的,高的隔离级别会导致并发性降低。对于索引字段,如果不指定区间范围,gap锁锁住的当前记录到下一个记录之间的间隙。在这个间隙里面不能插入数据。对于非索引字段,gap锁会锁住整个表看下面的分析

gap锁分析

有索引

一开始的时候数据如下:(age字段有普通索引)

有两个事务,事务(T1)查询age=12的。事务(T2)插入数据,age=10。结果如下:

插入会堵塞,gap锁会锁住age=12和第一个小于12数据之间的范围,因为这里还没有小于12的,所以,这里gap锁的范围是(-oo,12)。

age=10的数据已经插入了,还是上面的两个事务,事务(T1)查询age=12的。事务(T2)插入数据,age=8。结果如下:

插入不会堵塞,小于12的第一个数据是10,所以,这里gap锁锁住的范围是(10,12),插入8没有问题。

事务(T1)查询age=12的。事务(T2)插入数据,age=11。结果如下:

堵塞,因为这个时候gap锁的范围是(10,12),插入11肯定会堵塞。

没有索引

事务(T1)查询,事务(T2)插入数据age=10

注意,这里age字段没有索引,插入age=10的时候会堵塞。按照上面例子的结论,应该堵塞。没有问题。

事务(T1)查询,事务(T2)插入数据age=8

上面10的数据在事务t1提交之后,会插入成功。按照之前上一章节的例子的结论来说,这次的插入不应该堵塞,结果确实堵塞了。

结论分析

在有索引的字段中,索引的实现是B+树,都是有顺序的,比如age=12,只要锁住小于12的第一条数据和12之间的间隙就好了,别的区间和事务t1的查询没有关系,事务t1只关心age=12的数据,因为B+树的原因,他已经很明确的知道了可能会出现问题的地方,所以,只要锁住这个区间就好了。第一次插入数据,因为没有小于12的,gap锁锁的是(-oo,12),之后插入age=10,他只要锁住age=10和age=12的区间就好了,别的区间已经很明确的知道不会影响t1这次的查询。

在没有索引的字段中,锁住的是整个表,因为到处都有可能,没有B+树的加持,鬼知道哪里有可能。所以,直接锁住整个表。

gap锁退化

如果说,age字段上面是一个唯一索引,事务t1查询age=12,gap锁就不会去加之前的范围了,因为已经很明确了。唯一索引。别的插入数据和t1这次age=12查询没有关系,已经唯一索引已经保证不会在有age=12的数据出现。但是如果查询条件并不是一个唯一索引,gap锁该怎么弄,就怎么弄,因为不能确定唯一值。比如,student表中age和name加了一个唯一索引,但是查询条件确实age=12,这个时候gap锁不会退化。

Next-Key Locks

Next-key锁是Gap锁和Record锁的结合体。gap锁锁的是范围,record锁的是index,两个组合在一起就是next-key锁。

innoDB中的行级锁都是锁在索引上的。比如上面的例子age字段上面增加了索引,那么他的上锁的范围如下:

(negative infinity, 10]
(10, 11]
(11, 13]
(13, 20]
(20, positive infinity)

这里的例子可以结合上面gap锁的分析,索引记录中的下一个索引值也影响着gap锁的范围,但gap锁没有锁index的能力,他只是能阻止在这个区间里面不能插入数据。默认的情况下,next-key锁在RR隔离级别下使用。

Insert Intention Locks(插入意向锁)

插入意向锁是Insert操作在插入一行数据之前设置的一种间隙锁,它表示插入到同一个索引的不同事务如果没有插入到间隙中的同一个位置,则不需要等待。比如现在表中有两个字段,age=4和age=7,现在有两个插入数据的事务,事务t1想要插入age=5,事务t2想要插入age=6,他们并不会因为是同一个区间而冲突,每个事务在获取插入行的行锁之前先获取4和7之间的插入意向锁。

下面的例子展示了在获取插入的记录的独占锁之前先获取插入意图锁

事务t1给id大于100的防止排他锁,事务t2插入id等于101的数据。

表结构如下

CREATE TABLE child (id int(11) NOT NULL, PRIMARY KEY(id)) ENGINE=InnoDB;INSERT INTO child (id) values (90),(102);

show engine innoDB status看结果如下

AUTO-INC Locks(自动提交锁)

特别的表级别的锁,主要是为了AUTO_INCREMEN的列的值连续。如果一个事务在插入值,别的事务就要等待这个事务将数据插入到表中,这样AUTO_INCREMENT的列才能连续,

Predicate Locks for Spatial Indexes(空间索引的谓词判断锁)

它的出现主要是为了解决next-key锁在空间索引中不知道下一个键在哪里,计算不了,在B+树种,方向是递增的,很好计算,但是在空间索引中,next-key就不行了。


关于博客这件事,我是把它当做我的笔记,里面有很多的内容反映了我思考的过程,因为思维有限,不免有些内容有出入,如果有问题,欢迎指出。一同探讨。谢谢。

MySQL-InnoDB锁相关推荐

  1. MySQL InnoDB锁

    2019独角兽企业重金招聘Python工程师标准>>> InnoDB与MyISAM的最大不同有两点:一是支持事务(TRANSACTION):二是采用了行级锁.行级锁与表级锁本来就有许 ...

  2. MySQL InnoDB锁机制全面解析分享

    写在前面:在设计新零售供应链wms(仓库管理系统)库存模块时,为了防止并发情况对库存的影响,查阅了一些资料,对InnoDB锁机制有了更全面的了解,在此做出分享,如有疏漏望不吝指正,愿共同进步!(此篇为 ...

  3. MySQL InnoDB 锁介绍及不同 SQL 语句分别加什么样的锁

    作者:iceman1952(本文来自作者投稿) 本文中,我们详细介绍MySQL InnoDB存储引擎各种不同类型的锁,以及不同SQL语句分别会加什么样的锁. 阅读提示 1. 本文所参考的MySQL文档 ...

  4. mysql innodb 锁_MySQL/InnoDB锁机制

    显式加锁 select ... lock in share mode:加 S 锁 select ... for update:加 X 锁 MySQL快照读和当前读 在一个支持MVCC并发控制的系统中, ...

  5. mysql索引列是锁表还是锁行_[转]关于MYSQL Innodb 锁行还是锁表

    关于mysql的锁行还是锁表,这个问题,今天算是有了一点头绪,mysql 中 innodb是锁行的,但是项目中居然出现了死锁,锁表的情况.为什么呢?先看一下这篇文章. 做项目时由于业务逻辑的需要,必须 ...

  6. MySQL InnoDB 锁表与锁行

    2019独角兽企业重金招聘Python工程师标准>>> 由于InnoDB预设是Row-Level Lock,所以只有「明确」的指定主键,MySQL才会执行Row lock (只锁住被 ...

  7. mysql事务和锁innodb,MySQL - InnoDB 锁与事务(三)隔离级别与表的关系

    事务的隔离级别是用来调节数据库的并发性和数据的可靠性之间的平衡的工具.MySQL支持所有四种标准的隔离级别,Repeatable Read,Read Commited,Read Uncommited, ...

  8. mysql innodb 锁类型_详细介绍MySQL InnoDB存储引擎各种不同类型的锁

    本文中,我们详细介绍MySQLInnoDB存储引擎各种不同类型的锁,以及不同SQL语句分别会加什么样的锁. 阅读提示 1.本文所参考的MySQL文档版本是8.0,做实验的MySQL版本是8.0.13 ...

  9. MySQL行锁 表锁理解

    MySQL InnoDB 锁表与锁行 由于InnoDB预设是Row-Level Lock,所以只有「明确」的指定主键,MySQL才会执行Row lock (只锁住被选取的资料例) ,否则MySQL将会 ...

  10. Mysql锁专题:InnoDB锁概述

    一 概述 InnoDB与MyISAM有两处不同: 1)InnoDB支持事务: 2)默认采用行级锁(也可以支持表级锁) 对于更新操作(UPDATE.INSERT.DELETE),InnoDB会自动给涉及 ...

最新文章

  1. CentOS上使用libtld
  2. 深入理解计算机系统(2.7)------浮点数舍入以及运算
  3. 七月算法--12月机器学习在线班-第七次课笔记—最大熵
  4. 数据查询分页显示的优化方法
  5. 【Git】git stash应用场景
  6. P3515-[POI2011]Lightning Conductor【整体二分,决策单调性】
  7. LeetCode 1658. 将 x 减到 0 的最小操作数(哈希)
  8. 苹果双卡双待是哪一款_等12 mini还是买苹果11?实体店老板给出了答案,很有道理!...
  9. ES5和ES6类的知识
  10. USB 2.0 Spec 微缩版
  11. awg线径与电流_awg线径对照表(awg线径与电流对照表)
  12. PHP strtotime 将时间转换为时间戳
  13. Arduino相关函数
  14. phyton基础-01
  15. ADF7901BRUZ ASK/FSK发射器 ISM频段
  16. cmake的-G 参数
  17. 深度神经网络的成功应用,深度神经网络技术赋能
  18. 数据库管理工具哪个好?强力推荐Navicat Premium 16 mac中文版
  19. 微信公众号二维码海报自动生成,海报通推广有绝招
  20. 微信小程序----运动社区开发(一)

热门文章

  1. 用思维导图和孩子们一起了解“什么是春节”
  2. 数据库索引,到底是什么做的?-- 转自沈剑公众号
  3. STM32汇编语言点亮led灯
  4. 使用stm32配置自定义的HID设备
  5. 【STM32】RTC实时时钟,步骤超细详解,一文看懂RTC
  6. SpringBoot整合阿里云短信服务详细过程(保证初学者也能实现)
  7. GoLang之使用sync.Cond
  8. html调用一言api,纯 JavaScript 实现网站一言功能
  9. 《ASP.NET AJAX程序设计 第I卷 服务器端ASP.NET AJAX Extensions与ASP.NET AJAX Control Toolkit》目录(最终定稿)...
  10. Modern Family Season 1#01