Skip to content

DSTransactional与Transactional事务混用死锁场景分析

问题背景

最近在生产环境发现了死锁问题,经过排查发现是由于在使用@DSTransactional跨数据源注解时,混合使用了@Transactional注解,造成了同时对某个表中数据行的更新,导致了死锁。以此记录下排查的过程

问题流程图

问题流程图如下

问题现象

生产环境偶现死锁异常日志

部分业务执行成功一半,事务没有正常回滚

问题原因

如流程图所示 如果你的代码包含如下内容,那么就会造成死锁

java
@Autowired
private OtherDao otherDao;

@DSTransactional
public String testTransactional(Test test){
    // do business
    testMapper.updateStatus(test);
    otherDao.revoke(test);
    return "";
}

@Mapper
public class OtherDao implements IOtherDao{
    
    @Transactional
    public void revoke(Test test) {
        testMapper.update(test);
    }
}

这段代码描述了流程图中的事务顺序,先开启@DSTransactional,然后操作某一数据行,之后再开启@Transactional,操作同一数据行,由于@DSTransactional事务没有提交,等价于存在两个事务同时操作同一张表的同一行,产生了竞态,导致死锁发生

排查思路

1、找DBA要死锁日志找到死锁原因,或者有权限的情况下show engine innodb status\G,找到LATEST DETECTED DEADLOCK,再分析日志

2、根据日志排查代码,通常是因为事务的错误使用引起的

3、show processlist,查看当前执行情况,再来看代码

4、分析代码中是否有select读写锁,比如share modefor updateupdate更新同一行等可疑情况

解决方案

避免混合使用@DSTransactional@Transactional,因为@DSTransactional不支持事务传播机制,同时需要避免长事务