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

NestJS中如何无需传递事务绑定Prisma实例实现跨服务事务

解决NestJS中Prisma事务跨服务自动绑定的问题

方案:利用AsyncLocalStorage实现事务上下文传递

1. 创建Prisma上下文服务

封装一个PrismaContextService,通过AsyncLocalStorage存储和获取当前事务绑定的Prisma实例:

import { Injectable } from '@nestjs/common';
import { AsyncLocalStorage } from 'async_hooks';
import { PrismaClient } from '@prisma/client';

@Injectable()
export class PrismaContextService {
  private readonly als = new AsyncLocalStorage<PrismaClient>();

  // 将事务绑定的Prisma实例注入当前执行上下文
  runWithPrisma<T>(prisma: PrismaClient, callback: () => Promise<T>): Promise<T> {
    return this.als.run(prisma, callback);
  }

  // 获取上下文内的Prisma实例,无上下文时返回默认实例
  getPrisma(defaultPrisma: PrismaClient): PrismaClient {
    return this.als.getStore() ?? defaultPrisma;
  }
}

2. 修改PrismaService,集成上下文能力

改造原PrismaService,让所有操作优先从上下文读取事务绑定的实例:

import { Injectable, OnModuleInit, OnModuleDestroy } from '@nestjs/common';
import { PrismaClient } from '@prisma/client';
import { PrismaContextService } from './prisma-context.service';

@Injectable()
export class PrismaService extends PrismaClient implements OnModuleInit, OnModuleDestroy {
  constructor(private readonly prismaContext: PrismaContextService) {
    super();
    // 用动态代理自动拦截模型访问,无需逐个编写getter
    return new Proxy(this, {
      get(target, prop) {
        if (prop in target) {
          return Reflect.get(target, prop);
        }
        const prisma = target.prismaContext.getPrisma(target);
        return Reflect.get(prisma, prop);
      },
    }) as this;
  }

  async onModuleInit() {
    await this.$connect();
  }

  async onModuleDestroy() {
    await this.$disconnect();
  }

  // 重写$transaction方法,将事务实例注入上下文
  async $transaction<T>(fn: (prisma: PrismaClient) => Promise<T>): Promise<T> {
    return super.$transaction((tx) => {
      return this.prismaContext.runWithPrisma(tx, () => fn(tx));
    });
  }
}

3. 其他服务正常调用即可

UserService和OtherService无需修改,内部的Prisma操作会自动读取上下文里的事务实例:

@Injectable()
export class UserService {
  constructor(private readonly prismaService: PrismaService) {}

  async update(userId: string, data: Partial<User>) {
    // 若当前处于事务上下文,自动使用事务绑定的实例
    return this.prismaService.user.update({
      where: { id: userId },
      data,
    });
  }
}

4. 事务调用保持原有写法

OrdersService中的事务逻辑无需额外传递实例,跨服务操作会自动纳入同一事务:

@Injectable()
export class OrdersService {
  constructor(
    private readonly prismaService: PrismaService,
    private readonly userService: UserService,
    private readonly otherService: OtherService,
  ) {}

  async someFn() {
    return this.prismaService.$transaction(async () => {
      await this.userService.update('123', { name: 'Updated' });
      await this.otherService.delete('456');
    });
  }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.25 20:09:23