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

如何在NestJS中使用Transaction实现多表插入的原子操作

NestJS 多表插入事务实现方案

你当前的实现思路是正确的,仅需补充事务提交逻辑即可正常运行,QueryRunner绑定的事务上下文天然支持操作任意实体,不受单表限制。

你代码的核心遗漏点

你写的try块中所有操作执行成功后,没有调用await queryR.commitTransaction()提交事务,会导致所有操作最终都不会持久化到数据库。

修正后的完整代码

const queryR = this.connection.createQueryRunner();
await queryR.connect();
await queryR.startTransaction();

try {
  //## 运单实体操作 ##
  const shipmentToInsert = Transformador.prepareShipment(ShipConfirmDetails, ShipConfirmSummary)
  const shipmentInserted = await queryR.manager.save(shipmentToInsert)

  //## 订单实体操作 ##
  const ordersToInsert = Transformador.prepareOrder(ShipConfirmDetails, shipmentInserted.shipment_id)
  const orderedInserted = await queryR.manager.save(ordersToInsert)

  //## 明细实体操作 ##
  const linesToInsert = Transformador.prepareLines(ShipConfirmDetails, orderedInserted)
  const linesInserted = await queryR.manager.save(linesToInsert)

  // 新增:所有操作成功后提交事务
  await queryR.commitTransaction();
} catch (e) {
  console.log(">>出错,执行回滚>>");
  await queryR.rollbackTransaction();
  // 建议在这里抛出异常或者返回错误信息,方便上层逻辑感知事务失败
  throw e;
} finally {
  console.log(">>释放事务连接>>");
  await queryR.release();
}

可选优化:复用自定义Repository

如果你希望沿用之前封装好的Repository方法(比如你注释中的shipmentRepositoryService.insert),只需要通过当前QueryRunner的manager获取绑定了事务的Repository实例即可,无需修改原有Repository逻辑:

// 获取绑定当前事务的运单Repository
const transactionShipmentRepo = queryR.manager.getRepository(Shipment)
const shipmentInserted = await transactionShipmentRepo.insert(shipmentToInsert)

注意事项

  • 所有需要纳入事务的数据库操作,必须使用同一个QueryRunner实例导出的manager或Repository,不能混用全局注入的Repository,否则对应操作不会被事务管控,回滚时不会被撤销。
  • 建议在catch块中把错误抛出,方便上层业务逻辑感知事务执行结果,做对应的报错处理。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.29 02:24:00