如何在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
相关产品推荐
相关产品推荐

