暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

MySQL RC模式下奇怪的行锁探讨

原创 aisql 2024-10-16
320

1、问题复现

构造模拟数据

#模拟数据: DROP TABLE IF EXISTS T1; CREATE TABLE `t1` ( `id` int NOT NULL, `update_time` datetime DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (`id`) ) ENGINE=InnoDB; INSERT INTO t1(id) VALUES (1),(2),(3),(4),(5),(6),(7),(8),(10);
复制

session1 先执行 以下语句

-- session1 先执行 set session transaction_isolation='READ-COMMITTED'; begin; select * from t1 where id = 10 for update;
复制

session2 后执行 以下语句

-- session2 后执行 set session transaction_isolation='READ-COMMITTED'; begin; select * from t1 where id >= 7 and id <=8 for update;
复制

这里session2 会被session1堵塞。可以通过performance_schema.data_locks 观测锁的状态
image.png
通过performance_schema.data_locks 得知session2在等待session1 id=10的这行行锁。

2、问题探讨

问题1,为什么 session2 会需要id = 10的锁?

我们把上述两个事务均回滚,单独来看session2会锁哪些行
执行如下语句后

-- session2 先执行 set session transaction_isolation='READ-COMMITTED'; begin; select * from t1 where id >= 7 and id <=8 for update; select * from performance_schema.data_locks ;
复制

1729069747369.png

session2单独执行看它只需要锁7,8两行。

问题2, 将session2与 session1交换 就不会产生堵塞 为什么?
尝试1,我将session2与 session1执行顺序交换 两个session语句都能执行成功,并不会产生堵塞情况!
尝试2,将session2的语句加一个倒序排序

session1 先执行 以下语句

set session transaction_isolation='READ-COMMITTED'; begin; select * from t1 where id = 10 for update;
复制

session2 后执行 以下语句

-- session2 后执行 set session transaction_isolation='READ-COMMITTED'; begin; select * from t1 where id >= 7 and id <=8 order by id desc for update ;
复制

image.png
查看performance_schema.data_locks表。发现session2 按照排序顺序最后多锁了一行id=6的行

那由此推断,即使是RC隔离级别,也会按照排序顺序多锁一行!

尝试3,将session2的语句仍为升序,但session1 id变小

按此逻辑,换成升序将session语句也变一下。变成下面这样

session1 先执行 以下语句

set session transaction_isolation='READ-COMMITTED'; begin; select * from t1 where id = 6 for update;
复制

session2 后执行 以下语句

-- session2 后执行 set session transaction_isolation='READ-COMMITTED'; begin; select * from t1 where id >= 7 and id <=8 for update;
复制

image.png
但session2 却不会多锁一行。

所以只能再次推断,在这种模式下仍会尝试按语句尝试多锁一行,只是发现不符合语句条件又释放掉了

问题3 但为什么倒序的时候又不释放多锁的一行呢?

以上的推断只是依据结果做的猜想,如果哪位在这个例子情况下有更严谨的解答,欢迎回复指导!

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

评论

目录
  • 1、问题复现
  • 2、问题探讨
    • 问题1,为什么 session2 会需要id = 10的锁?
    • 问题2, 将session2与 session1交换 就不会产生堵塞 为什么?
    • 尝试1,我将session2与 session1执行顺序交换 两个session语句都能执行成功,并不会产生堵塞情况!
    • 尝试2,将session2的语句加一个倒序排序
    • 尝试3,将session2的语句仍为升序,但session1 id变小
    • 问题3 但为什么倒序的时候又不释放多锁的一行呢?