数据库版本:阿里云RDS 5.7 隔离级别:RC
表结构:t (
id bigint(20) NOT NULL AUTO_INCREMENT,
a datetime,
b bigint(20),
c varchar(255),
d bigint(20),
e varchar(50),
f int(11),
PRIMARY KEY (id)
);
产生死锁的业务代码(仅贴出伪代码):
@Transactional
public void update(String s) {
for (int i = 1; i < 6; i++) {
update t set ... where e = #{s} and f = #{i};
}
}
该事务在并发场景下发生死锁,求大神解释一下为什么会死锁?
本问题来自阿里云开发者社区的【11大垂直技术领域开发者社群】。 https://developer.aliyun.com/article/706511 点击链接欢迎加入感兴趣的技术领域群
版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。
在您提供的场景中,死锁发生的原因可能涉及到事务并发执行时对相同资源的锁定顺序不一致。具体到您的代码和数据库操作,可以分析如下:
事务隔离级别为RC(Read Committed,读已提交):这意味着在一个事务中,只能看到已经提交的修改。虽然RC降低了可重复读的保证,但在这个场景下,它不是直接导致死锁的因素。
循环中的更新操作:在update(String s)
方法中,您有一个循环,每次循环都会尝试更新表t
中满足条件a = s
的记录的列b
。这里的关键在于,每次循环都是基于同一个查询条件s
,并且是在一个事务中连续执行多次更新。
死锁产生的原因:
update
方法,并且分别传入了不同的参数s1
和s2
,使得它们各自锁定并尝试更新不同的行。s1
的行的锁,并开始更新。此时,线程B也执行,获取到了满足条件s2
的行的锁。s1
的行),而线程A又试图更新线程B锁定的行(即满足条件s2
的行),就会形成一个相互等待的循环,即死锁。解决办法:
综上所述,死锁是由于并发事务按照不同顺序请求相同的锁资源,且每个事务都已经持有了对方需要的锁,而又都不释放自己的锁所造成的。通过调整事务策略、优化SQL执行逻辑等方法可以有效避免此类问题。