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

MikroORM @Transactional装饰器在MongoDB中无法正常工作求助

MikroORM @Transactional装饰器无法持久化数据,回调模式正常

我是MikroORM新手,使用@Transactional装饰器的create方法时,无报错但用户数据无法持久化到MongoDB Atlas;改用em.transactional回调实现的create2方法时,数据能正常持久化并返回带ObjectId的用户对象。以下是相关代码,求解决方法。

Model

import { Entity, PrimaryKey, Property } from '@mikro-orm/core';
import { ObjectId } from 'mongodb';

@Entity()
export class User {
  @PrimaryKey()
  _id!: ObjectId;

  @Property()
  name!: string;

  @Property()
  phone!: string;

  constructor(name: string, phone: string) {
    this.name = name;
    this.phone = phone;
  }
}

Fastify路由

...

fastify.post('/users', async function (request, reply): Promise<User> {
  const userData = request.body as Omit<User, '_id'>
  try {
    const user: User = await new UserService(getEM()).create(userData)
    console.log('Created user:', user)
    return user
  } catch (error) {
    console.error('Error creating user:', error)
    throw error
  }
})

...

Service类

import { ObjectId } from 'mongodb'
import { User } from '../models/user'
import { EntityManager, Transactional } from '@mikro-orm/core'

class UserService {
    constructor(private readonly em: EntityManager) { }

    @Transactional()
    async create(userData: Omit<User, '_id'>): Promise<User> {
        const user: User = this.em.create(User, userData)
        this.em.persist(user);
        return user
    }

    async create2(userData: Omit<User, '_id'>): Promise<User> {
        return await this.em.transactional(em => {
            const user: User = em.create(User, userData)
            em.persist(user);
            return user
        })
    }
}

export { UserService }

MikroORM配置

import { MikroORM, EntityManager } from '@mikro-orm/core';
import { MongoDriver } from '@mikro-orm/mongodb';
import { User } from '../user/models/user';
import Config from './config';
import Question from '../question/models/question';

interface DatabaseConfig {
  url: string,
  debug?: boolean,
}

const config: any = Config.get()
const dbconf: DatabaseConfig = config && config.database ? config.database : {} as DatabaseConfig
const url = process.env.DATABASE_URL ?? dbconf.url

let orm: MikroORM<MongoDriver> | null = null;
let em: EntityManager | null = null;

export async function initORM() {
  orm = await MikroORM.init<MongoDriver>({
    entities: [User, Question],
    clientUrl: url,
    driver: MongoDriver,
    debug: true,
  });

  em = orm.em;
  return orm;
}

export function getORM(): MikroORM<MongoDriver> {
  if (!orm) {
    throw new Error('ORM not initialized. Call initORM() first.');
  }
  return orm;
}

export function getEM(): EntityManager {
  if (!em) {
    throw new Error('EntityManager not initialized. Call initORM() first.');
  }
  return em.fork();
}

问题原因及解决方法

  1. 核心问题:@Transactional装饰器需要依赖RequestContext上下文才能生效,手动传入的EntityManager实例无法被装饰器正确拦截替换,导致事务逻辑未执行,数据未持久化。

  2. 具体修复步骤:

步骤1:添加RequestContext中间件

在Fastify初始化时注入上下文管理中间件:

import { RequestContext } from '@mikro-orm/core';

fastify.addHook('onRequest', async (request, reply) => {
  RequestContext.create(getORM().em);
});

步骤2:修改Service类获取EntityManager

不再手动传入EntityManager,改为从上下文自动获取:

import { RequestContext } from '@mikro-orm/core';

class UserService {
    private get em(): EntityManager {
        return RequestContext.getEntityManager();
    }

    @Transactional()
    async create(userData: Omit<User, '_id'>): Promise<User> {
        const user: User = this.em.create(User, userData)
        this.em.persist(user);
        return user
    }

    // create2方法保持不变
}

步骤3:调整路由中的Service实例化

fastify.post('/users', async function (request, reply): Promise<User> {
  const userData = request.body as Omit<User, '_id'>
  try {
    const user: User = await new UserService().create(userData) // 不再传入getEM()
    console.log('Created user:', user)
    return user
  } catch (error) {
    console.error('Error creating user:', error)
    throw error
  }
})

原理说明

@Transactional装饰器会在RequestContext上下文内自动创建事务专用的EntityManager,替换当前上下文实例。如果没有上下文,装饰器无法绑定事务逻辑,导致persist操作仅停留在内存中,未触发数据库写入。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.11 22:12:47