Nestjs:如何使用mongoose启动一个会话进行事务处理?

kkbh8khc  于 2023-01-13  发布在  Go
关注(0)|答案(2)|浏览(254)

使用事务的mongoose文档非常简单,但是当在nestjs中使用它时,它会返回一个错误:

Connection 0 was disconnected when calling `startSession`
MongooseError: Connection 0 was disconnected when calling `startSession`
    at NativeConnection.startSession

我的代码:

const transactionSession = await mongoose.startSession();
    transactionSession.startTransaction();

    try
    {
      const newSignupBody: CreateUserDto = {password: hashedPassword, email, username};
  
      const user: User = await this.userService.create(newSignupBody);

      //save the profile.
      const profile: Profile = await this.profileService.create(user['Id'], signupDto);

      const result:AuthResponseDto = this.getAuthUserResponse(user, profile);

      transactionSession.commitTransaction();
      return result;
    }
    catch(err)
    {
      transactionSession.abortTransaction();
    }
    finally
    {
      transactionSession.endSession();
    }
fivyi3re

fivyi3re1#

我研究了@nestjs/mongoose后找到了解决方法,这里的mongoose里面没有连接,这就是返回错误的原因。
解决方案:

import {InjectConnection} from '@nestjs/mongoose';
import * as mongoose from 'mongoose';

在服务类的构造函数中,我们需要添加服务可以使用的连接参数。

export class AuthService {
constructor(
  // other dependencies...
  @InjectConnection() private readonly connection: mongoose.Connection){}

代替

const transactionSession = await mongoose.startSession();
transactionSession.startTransaction();

我们现在将使用:

const transactionSession = await this.connection.startSession();
transactionSession.startTransaction();

这样,就可以解决startSession()后断开连接的问题。

pbpqsu0x

pbpqsu0x2#

除了Noobish提供的答案之外,我还想演示一个我在项目中使用的可重用函数:

import { ClientSession, Connection } from 'mongoose';

export async function transaction<T>(connection: Connection, cb: (session: ClientSession) => Promise<T>): Promise<T> {
  const session = await connection.startSession();

  let result: T;
  await session.withTransaction(async (s) => {
    result = await cb(s);
  });

  await session.endSession();
  
  return result;
}

然后可以这样使用它:

@Injectable()
export class MyService {
  constructor(
    @InjectModel(MyModel.name) private myModel: Model<MyModelDocument>,
    @InjectConnection() private connection: Connection,
  ) {}

  async find(id: string): Promise<MyModel> {
    return transaction(this.connection, async (session) => {
      return this.myModel
        .findOne(id)
        .session(session)
        .exec();
    });
  }

显然,如果内部调用包含单个返回,则可以省略内部闭包,从而使用可读性更强/更紧凑的版本。

相关问题