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(); }
问题原因及解决方法
核心问题:
@Transactional装饰器需要依赖RequestContext上下文才能生效,手动传入的EntityManager实例无法被装饰器正确拦截替换,导致事务逻辑未执行,数据未持久化。具体修复步骤:
步骤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
相关产品推荐
相关产品推荐

