暂无图片
暂无图片
7
暂无图片
暂无图片
4
暂无图片

深入理解MySQL锁 (S、X、IS、IX)RC模式下解析

原创 aisql 2022-01-06
5906

一、定义:

S锁:共享锁,行级锁,已加S锁的行,不允许其它事务再加X锁,但可以继续加S锁
X锁:排它锁,行级锁,已加X锁的行,不允行其它事务再加S或X锁

IS:意向共享锁,表级锁,已加S锁的表,肯定会有IS锁,反过来,有IS锁的表,不一定会有S锁
IX:意向排它锁,表级锁,已加X锁的表,肯定会有IX锁,反过来,有IX锁的表,不一定会有X锁

二、准备工作

我使用的MySQL版本为8.0.26
我使用的是MySQL Workbench 开两个连接,并确保隔离级别为RC,因这篇文章主要讲RC

所以请注意,后面讲产生的锁的情况如果没有特别标注,都是在RC隔离级别下。

先查看

select @@global.transaction_isolation,@@transaction_isolation;
复制

查看结果
REPEATABLE-READ REPEATABLE-READ

将当前session隔离级别改为 RC

set session transaction isolation level read committed;
复制

三、测试数据

为了读者可复现,我这里先构造数据

CREATE TABLE `test_store` ( `tid` int(10) unsigned NOT NULL, `storeid` int(10) unsigned NOT NULL COMMENT '仓库ID', `storecode` varchar(50) NOT NULL COMMENT '仓库编号', PRIMARY KEY (`tid`,`storeid`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; insert into test_store select 1,2,'bb' union all select 1,1,'AA'; CREATE TABLE `test_goodsbound` ( `tid` int(10) unsigned NOT NULL, `goodsid` int(10) unsigned NOT NULL, `storeid` int(10) unsigned NOT NULL, PRIMARY KEY (`tid`,`goodsid`,`storeid`), KEY `fk_goodsbound_storeid` (`tid`,`storeid`), CONSTRAINT `fk_goodsbound_storeid` FOREIGN KEY (`tid`, `storeid`) REFERENCES `test_store` (`tid`, `storeid`) ON DELETE NO ACTION ON UPDATE NO ACTION ) ENGINE=InnoDB DEFAULT CHARSET=utf8; insert into test_goodsbound select 1,1,1 union all select 1,2,1 union all select 1,3,1;
复制

四、产生锁的行为

什么行为会产生S锁?

1、主动 在select 后添 加 lock in share mode

begin; select 1 from test_goodsbound where tid = 1 lock in share mode
复制

然后查看锁的情况,如下图

select * from performance_schema.data_locks;
复制

16414501331.png

可以看到在相关的上加了S锁,表上也有了IS锁

2、对含有外键的表进行修改,会让外键对应的表加上S锁

参看上面的表结构,test_goodsbound 表存在一个外键 fk_goodsbound_storeid

begin; update test_goodsbound set goodsid =10 where tid = 1 and goodsid = 3
复制

然后查看锁的情况,如下图

select * from performance_schema.data_locks;
复制

16414518581.png
看第4行数据,test_store表 的tid = 1 storeid = 1的行 添加了S锁、当然第一行也对 test_store表添加了 IS锁

外键只有insert,update表才会对外键数据所对应的主键表所在的行 增加 S锁。

delete 不会产生

begin; delete from test_goodsbound
复制

然后查看锁的情况,如下图

select * from performance_schema.data_locks;
复制

16414523591.png


这个也是我不推荐使用数据库外键约束的原因。增加S锁,就增大了死锁概率。让应用自己检查判断保证完整性。

3、在RR上还有一次情况会产生S锁

先将改隔级别改为 RR

set session transaction isolation level REPEATABLE READ
复制

执行下列语句

INSERT INTO test_goodsbound2(tid,storeid,goodsid) select tid,storeid,goodsid from ( select tid,storeid,goodsid,sleep(10) from test_goodsbound limit 100) as t
复制

在另一个连接上查看锁的情况

select * from performance_schema.data_locks;
复制

16414533581.png

隔10秒后,再执行

image.png


你会发现,多了一行。 所以只有这种情况很特殊,select 扫一行,就会添加一行的S锁。

什么行为会产生X锁?

1、主动 在select 后添加 for update

begin; select * from test_goodsbound where tid = 1 and goodsid = 1 for update
复制

然后查看锁的情况,如下图

select * from performance_schema.data_locks;
复制

16414554341.png

如果所涉及的查询或修改走了二级索引,则会连二级索引一起上锁。

explain select * from test_goodsbound where tid = 1 and storeid = 1 for update
复制

16414555301.png

可以看到 这个select语句,走了二级索引

begin; select * from test_goodsbound where tid = 1 and storeid = 1 for update
复制

然后查看锁的情况,如下图

select * from performance_schema.data_locks;
复制

16414556041.png

会看到,主键索引与二级索引相关行上都添加了X锁

2、执行 insert,update,delete语句,对所涉及的行

begin; delete tg from test_goodsbound as tg force index(fk_goodsbound_storeid ) where tid = 1 and storeid = 1
复制

我这里强制走了二级索引 fk_goodsbound_storeid
然后查看锁的情况,如下图

select * from performance_schema.data_locks;
复制

16414558691.png

五、兼容与互斥

贴一个兼容表格
16414561541.png

我对红框中的互斥做一个试验

先产生一个只有IS锁的 事务

begin; select * from test_goodsbound where tid = 1 and storeid = 2 lock in share mode
复制

然后查看锁的情况,如下图

select * from performance_schema.data_locks;
复制

16414565711.png

打开另一个连接,执行

insert into test_goodsbound values(1,1,2);
复制

再执行

delete from test_goodsbound where tid = 1 and storeid = 2
复制

都是可以执行的。


所以我认为,如果只有IS锁,没有对应的记录有S锁,那么IS 与 行X是不互斥的,但与表X是互斥的。

我们再来检查一下,IX与X与S的互斥

begin; select * from test_goodsbound where tid = 1 and storeid = 2 for update
复制

然后查看锁的情况,如下图

select * from performance_schema.data_locks;
复制

16414568161.png

同样,在另一个连接中去执行

打开另一个连接,执行

insert into test_goodsbound values(1,1,2);
复制

再执行

delete from test_goodsbound where tid = 1 and storeid = 2
复制

都是可以执行的。


所以我同样认为,如果只有IX锁,没有对应的记录有X锁,那么IX 与 行S和行X是不互斥的,但与表X与表S锁是互斥的。

2024-05-17更新

因为IX与IS是表级锁,而S与X锁即有表级也有行级,表格上没有区分出来

IX与表级S锁与X锁是互斥的,与行级S与X是不互斥的
IS与表级X锁是互斥的,与行级S与X是不互斥的


另外的互斥,我就不一一试验了。

如文章中有问题,也欢迎大家指正。谢谢。

欢迎大家关注我的微信公众号,分享MySQL相关知识
扫码_搜索联合传播样式白色版.png

最后修改时间:2025-01-16 19:29:49
「喜欢这篇文章,您的关注和赞赏是给作者最好的鼓励」
关注作者
【版权声明】本文为墨天轮用户原创内容,转载时必须标注文章的来源(墨天轮),文章链接,文章作者等基本信息,否则作者和墨天轮有权追究责任。如果您发现墨天轮中有涉嫌抄袭或者侵权的内容,欢迎发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论

^_^
暂无图片
2年前
评论
暂无图片 1
https://dev.mysql.com/doc/refman/8.0/en/innodb-locking.html#:~:text=intention%20locks%20do%20not%20block%20anything%20except%20full%20table%20requests%20(for%20example%2C%20lock%20tables%20...%20write).%20the%20main%20purpose%20of%20intention%20locks%20is%20to%20show%20that%20someone%20is%20locking%20a%20row%2C%20or%20going%20to%20lock%20a%20row%20in%20the%20table.
2年前
暂无图片 1
评论
^_^
暂无图片
2年前
评论
暂无图片 0
因为IX,IS 是表级锁,针对行级的S、X锁不产生冲突。当你进行表级的S、X操作时,那个表才生效。
2年前
暂无图片 点赞
1
chengang
暂无图片
2年前
回复
暂无图片 0
谢谢指教,所以那个表该更细一些,把表级S,行级S,表级X,行级X分开
2年前
暂无图片 点赞
回复
墨天轮福利君
暂无图片
3年前
评论
暂无图片 0
您好,您的文章已入选合格奖,10墨值奖励已经到账请查收! ❤️我们还会实时派发您的流量收益。
3年前
暂无图片 点赞
评论
chengang
暂无图片
关注
暂无图片
获得了897次点赞
暂无图片
内容获得231次评论
暂无图片
获得了297次收藏
TA的专栏
MySQL生产实战优化
收录15篇内容
有意思的SQL
收录13篇内容
MySQL事务
收录2篇内容
目录
  • 一、定义:
  • 二、准备工作
  • 三、测试数据
  • 四、产生锁的行为
    • 什么行为会产生S锁?
      • 1、主动 在select 后添 加 lock in share mode
      • 2、对含有外键的表进行修改,会让外键对应的表加上S锁
      • 3、在RR上还有一次情况会产生S锁
    • 什么行为会产生X锁?
      • 1、主动 在select 后添加 for update
      • 2、执行 insert,update,delete语句,对所涉及的行
  • 五、兼容与互斥