Sequelize并发请求时事务重复回滚报错,如何实现请求独立事务?
问题分析与解决方案
问题根源
你遇到的错误是因为事务未在所有分支路径中正确清理,且部分场景下重复操作了同一个事务实例:
- 当
getConsumerBalance抛出错误时,直接通过return next(err)返回,未rollback已创建的事务,导致事务占用连接池资源,后续请求可能复用异常连接。 - 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
相关产品推荐
相关产品推荐

