You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Sequelize并发请求时事务重复回滚报错,如何实现请求独立事务?

问题分析与解决方案

问题根源

你遇到的错误是因为事务未在所有分支路径中正确清理,且部分场景下重复操作了同一个事务实例:

  1. 当getConsumerBalance抛出错误时,直接通过return next(err)返回,未rollback已创建的事务,导致事务占用连接池资源,后续请求可能复用异常连接。
  2. catch块中调用transaction.rollback()时未处理自身可能抛出的错误,若rollback过程中出现异常,可能导致同一事务被重复操作。

修复步骤

1. 补全所有分支的事务清理

在getConsumerBalance的错误分支中,先rollback事务再返回错误:

try {
    consumer = await getConsumerBalance(account_no);
} catch (err) {
    logger.error(err);
    // 新增:rollback已创建的事务,避免连接泄漏
    await transaction.rollback();
    return next(err);
}

2. 给rollback添加错误处理

避免rollback自身异常导致的重复事务操作:

catch (err) {
     if (!isCommitted) {
        try {
            await transaction.rollback();
        } catch (rollbackErr) {
            logger.error('事务回滚失败:', rollbackErr);
        }
     }
  
    logger.error(err);
    next(err);
}

3. 确保事务操作的原子性

在transaction.commit()之后立即返回,避免后续代码意外修改事务状态:

await transaction.commit();
isCommitted = true;

return res.send({ 
    success: true, 
    timestamp: dayjsDate.unix(),
    payment_date: d.payment_date,
    payment_time: d.payment_time,
    payment_amount: d.payment_amount,
    total_bill: consumer.total_bill,
    outstanding_bill: 0
});

4. 验证事务独立性

当前代码中const transaction = await DB.MAINDB.transaction()的写法是正确的——每个请求都会创建独立的事务实例,无需修改DB单例配置。只需确保:

  • 所有数据库操作都显式传入当前请求的transaction参数
  • 事务在成功提交或失败回滚后,不会被再次操作

额外建议

  • 升级Sequelize到最新稳定版本,避免旧版本的事务并发bug
  • 监控连接池状态,若请求量远超配置的max:50,可适当调高连接池上限
  • 对getConsumerBalance这类查询,若无需事务控制,保持其独立查询即可,不要绑定到当前事务

内容的提问来源于stack exchange,提问作者Julius Guevarra

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.04 11:35:31