import { Injectable } from '@nestjs/common'; import { DataSource, QueryRunner, EntityManager } from 'typeorm'; /** * Transaction Service - 提供可靠的事务管理 * * 基于 TypeORM 官方推荐的 QueryRunner 模式 * 参考: https://typeorm.io/docs/advanced-topics/transactions/ */ @Injectable() export class TransactionService { constructor(private readonly dataSource: DataSource) {} /** * 在事务中执行操作 (推荐使用) * * @param operation - 接收 EntityManager 的异步操作函数 * @returns 操作的返回值 * @throws 如果操作失败,事务会自动回滚并抛出原始错误 * * @example * ```typescript * const result = await this.transactionService.runInTransaction(async (manager) => { * await manager.save(PaymentORM, payment); * await manager.update(OrderORM, orderId, { status: 'PAID' }); * return payment; * }); * ``` */ async runInTransaction( operation: (manager: EntityManager) => Promise, ): Promise { const queryRunner = this.dataSource.createQueryRunner(); await queryRunner.connect(); await queryRunner.startTransaction(); try { const result = await operation(queryRunner.manager); await queryRunner.commitTransaction(); return result; } catch (error) { await queryRunner.rollbackTransaction(); throw error; } finally { // 重要:必须释放连接,否则会导致连接池耗尽 await queryRunner.release(); } } /** * 使用 QueryRunner 执行事务 (用于需要更多控制的场景) * * @param operation - 接收 QueryRunner 的异步操作函数 * @returns 操作的返回值 * * @example * ```typescript * const result = await this.transactionService.runWithQueryRunner(async (queryRunner) => { * // 可以使用 queryRunner.manager 进行操作 * // 也可以使用 queryRunner.query() 执行原始 SQL * await queryRunner.manager.save(entity); * return entity; * }); * ``` */ async runWithQueryRunner( operation: (queryRunner: QueryRunner) => Promise, ): Promise { const queryRunner = this.dataSource.createQueryRunner(); await queryRunner.connect(); await queryRunner.startTransaction(); try { const result = await operation(queryRunner); await queryRunner.commitTransaction(); return result; } catch (error) { await queryRunner.rollbackTransaction(); throw error; } finally { await queryRunner.release(); } } /** * 使用乐观锁执行更新 (防止并发覆盖) * * @param operation - 异步操作函数 * @param maxRetries - 最大重试次数 (默认 3) * @returns 操作的返回值 * @throws 如果达到最大重试次数仍失败 * * @example * ```typescript * await this.transactionService.runWithOptimisticLock(async (manager) => { * const payment = await manager.findOne(PaymentORM, { where: { id } }); * payment.status = 'COMPLETED'; * await manager.save(payment); // 如果 version 不匹配会抛出错误 * }); * ``` */ async runWithOptimisticLock( operation: (manager: EntityManager) => Promise, maxRetries: number = 3, ): Promise { let lastError: Error | null = null; for (let attempt = 1; attempt <= maxRetries; attempt++) { try { return await this.runInTransaction(operation); } catch (error: unknown) { // TypeORM 乐观锁冲突错误 if ( error instanceof Error && (error.name === 'OptimisticLockVersionMismatchError' || error.message.includes('version')) ) { lastError = error; // 短暂延迟后重试 await this.delay(50 * attempt); continue; } throw error; } } throw new Error( `Optimistic lock failed after ${maxRetries} retries: ${lastError?.message}`, ); } private delay(ms: number): Promise { return new Promise((resolve) => setTimeout(resolve, ms)); } }