spring声明式事务未提交引发的线上问题

1、现象

接收到kafka传来的b类信息(分a,b两类,b类的一些处理依赖a类)处理异常邮件,处理后,发现有一个pod日志打印数据库连接失败,重启后,某业务监控页面一直告警,并且两个pod都停止消费文件,都重启后,恢复正常

2、根因分析

实际重启pod,也只是临时解决问题,并未解决根因,还会出现相似问题,所以要分析根因并解决

1)找到DBA查看数据库使用情况,发现相关表出现阻塞的情况,导致无法处理文件

2)排查代码问题,发现几处业务代码使用手动事务时,在特殊情况无法关闭

3)第一处xxljob触发的定时任务A,每日执行,只会触发pod1

DefaultTransactionDefinition def =new DefaultTransactionDefinition();
def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW);
TransactionStatus transactionStatus = transactionManager.getTransaction(def);
try{
    if (arrayList.size() > 0) {
        // 执行业务
        transactionManager.commit(transactionStatus);
    }
} catch(Exception e){
    log.error(" " ,e);
    transactionManager.rollback(transactionStatus);
}

当arrayList为空时,永远无法释放资源,所以在一定时间后,该pod无法连接数据库

4)第二处是处理Kafka信息的代码,由于pod1无法连接数据库,导致一些a类信息在pod1无法处理,而相关的b类消息被分配到pod2时,运行如下代码,会无法释放数据库连接

DefaultTransactionDefinition def = new DefaultTransactionDefinition();
def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW);
TransactionStatus transactionStatus = transactionManager.getTransaction(def);
Orders order = 查询语句;
if (Objects.isNull(order)) {
    try {
         //业务代码
         transactionManager.commit(transactionStatus);
         return orderData;
    } catch (Exception e) {
         transactionManager.rollback(transactionStatus);
         throw new BusinessException(e.getMessage());
    }
}

5)在4)中的spring线程会在一定时间后被收回,而这个线程中存在未提交的事务,而消费文件的代码会获取到该类线程,此处代码有手动在数据库加锁、解锁的业务,这会导致相关表被阻塞,导致无法消费文件

3、解决方法

1)编程式事务改为声明式

2)增加数据库连接

3)增加监控

4)增加手动处理文件接口

参考文章:MySQL中Spring管理的事务开启后不提交引起的事故_spring开启了一个事物不提交也不回滚会产生问题吗-CSDN博客

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值