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

NestJS + TypeORM(0.3x) 自定义仓库事务使用问题及替代方案咨询

问题

我在NestJS中通过以下方式创建自定义仓库:

iuser.repository.ts

import { UserEntity } from "../entity/user-entity";

export interface IUserRepository {
    findByEmail(email: string): Promise<UserEntity>
}

user.repository.ts

import { Injectable } from "@nestjs/common";
import { InjectRepository } from "@nestjs/typeorm";
import { UserEntity } from "src/user/domain/entity/user-entity";
import { IUserRepository } from "src/user/domain/repository/iuser.repository";
import { Repository } from "typeorm";

@Injectable()
export class UserRepository extends Repository<UserEntity> implements IUserRepository {
    constructor(
        @InjectRepository(UserEntity)
        private readonly userRepository: Repository<UserEntity>
    ) {
        super(UserEntity, userRepository.manager)
    }

    async findByEmail(email: string): Promise<UserEntity> {
        return await this.userRepository
            .createQueryBuilder()
            .where('email = :email', { email })
            .getOne();
    }
}

在服务中使用事务时,调用queryRunner.manager.withRepository(this.userRepository)编译无报错,但运行时抛出以下错误:

if (this.isReleased) throw new QueryRunnerAlreadyReleasedError()
                           ^
QueryRunnerAlreadyReleasedError: Query runner already released. Cannot run queries anymore.

日志显示通过withRepository生成的新仓库实例的manager和queryRunner均为undefined。我知道withRepository应该生成绑定当前事务manager的自定义仓库实例,但不知道怎么正确使用。请问除了TypeORM文档里的getRepository().extend方法外,怎么在事务中用我这种方式实现的自定义仓库?

解决方案

你的自定义仓库实现存在两个核心问题:一是继承Repository时冗余注入了基础仓库实例,二是自定义方法直接依赖原始注入的仓库而非当前实例的manager。调整如下:

1. 重构自定义仓库,修正初始化逻辑

修改user.repository.ts,完整传递父类初始化参数,并让自定义方法使用当前实例的上下文:

import { Injectable } from "@nestjs/common";
import { InjectRepository } from "@nestjs/typeorm";
import { UserEntity } from "src/user/domain/entity/user-entity";
import { IUserRepository } from "src/user/domain/repository/iuser.repository";
import { Repository } from "typeorm";

@Injectable()
export class UserRepository extends Repository<UserEntity> implements IUserRepository {
    constructor(
        @InjectRepository(UserEntity)
        repository: Repository<UserEntity>
    ) {
        // 完整传递target、manager、queryRunner,保证实例上下文可被正确替换
        super(repository.target, repository.manager, repository.queryRunner);
    }

    async findByEmail(email: string): Promise<UserEntity> {
        // 使用当前实例的createQueryBuilder,确保绑定正确的事务上下文
        return this.createQueryBuilder()
            .where('email = :email', { email })
            .getOne();
    }
}

2. 事务中正确获取绑定事务的仓库实例

在服务中使用事务时,改用queryRunner.manager.getCustomRepository获取绑定当前事务的自定义仓库:

import { Injectable } from '@nestjs/common';
import { UserRepository } from './user.repository';
import { getConnection } from 'typeorm';

@Injectable()
export class UserService {
    constructor(
        private readonly userRepository: UserRepository
    ) {}

    async someTransactionalOperation() {
        const connection = getConnection();
        const queryRunner = connection.createQueryRunner();
        
        await queryRunner.connect();
        await queryRunner.startTransaction();

        try {
            // 获取绑定当前事务的自定义仓库实例
            const txUserRepo = queryRunner.manager.getCustomRepository(UserRepository);
            
            // 执行事务内操作
            const user = await txUserRepo.findByEmail('test@example.com');
            // ...其他数据库操作

            await queryRunner.commitTransaction();
            return user;
        } catch (err) {
            await queryRunner.rollbackTransaction();
            throw err;
        } finally {
            await queryRunner.release();
        }
    }
}

关键说明

  • 父类初始化必须传递target、manager、queryRunner三个参数,这样TypeORM才能在事务场景中正确替换实例的上下文。
  • 自定义方法必须使用this.createQueryBuilder(),而非依赖注入的原始仓库,确保操作绑定当前实例的manager/queryRunner。
  • 事务场景下用getCustomRepository替代withRepository,TypeORM会自动基于当前事务的manager生成新的自定义仓库实例,保证所有操作都在事务内执行。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.21 04:28:32