我尝试将这种责任具体化到某个地方,而不是必须声明一个新的 prisma.$transaction 来获取能够自动回滚我需要的每个 api 请求的 prisma 实例。
目前我最好的尝试是一个事务中间件,它可以工作,我可以准确地声明我需要的位置,并通过请求或参数装饰器接收控制器上的 prisma 实例(因为我使用的是 Nest)。
import { Injectable, NestMiddleware } from '@nestjs/common'
import { Request, Response, NextFunction } from 'express'
import { PrismaService } from '../prisma.service'
@Injectable()
export class TransacitonMiddleware implements NestMiddleware {
constructor(private readonly prisma: PrismaService) {}
async use(req: Request, res: Response, next: NextFunction) {
await this.prisma.$transaction(async (instance) => {
req['prisma'] = instance
next() // => GET /user
})
}
}
import {
Controller,
Get,
Req
} from '@nestjs/common'
@Controller('users')
export class UsersController {
@Get()
async findAll(@Req() request: any) {
const { prisma } = request
const users = await prisma.user.findMany()
return users
}
}
但是,prisma 请求需要在 prisma.$transaction 仍处于打开状态时发出,并且由于 Express Next 功能的同步行为,事务将始终在请求结束之前关闭。
Error:
Invalid `prisma.user.findMany()` invocation in .../users.controller.ts:35:37
32 async findAll(@Req() request: any) {
33 const { prisma } = request
34
→ 35 const users = await prisma.user.findMany(
Transaction API error: Transaction already closed: A query cannot be executed on a committed transaction. at An.handleRequestError...
首先,我尝试以某种方式使 nextFunction 异步,在其上放置一个等待,将其放入异步函数中,但都不起作用。
然后我尝试以某种方式延长事务的生命周期,我在中间件内的下一个函数之后声明了另一个 prisma 请求并且它起作用了。
async use(req: Request, res: Response, next: NextFunction) {
await this.prisma.$transaction(async (instance) => {
req['prisma'] = instance
next() // => GET /user
await instance.user.count()
})
}
但是,由于显而易见的原因,我认为这不是一个好的做法,而且我目前已经用尽了我的选择和时间来交付这个。因此,如果有人对如何实现此功能有任何想法,请做出贡献。
感谢大家的时间和考虑!