NestJS中的Mikro orm服务间事务
我正在为未来的项目评估Mikro Orm。有几个问题我要么在文档中找不到答案,要么没有完全理解 让我描述一个最简单的复杂示例(NestJS):我有一个订单处理系统,它有两个实体:NestJS中的Mikro orm服务间事务,nestjs,mikro-orm,Nestjs,Mikro Orm,我正在为未来的项目评估Mikro Orm。有几个问题我要么在文档中找不到答案,要么没有完全理解 让我描述一个最简单的复杂示例(NestJS):我有一个订单处理系统,它有两个实体:订单和发票,以及一个用于顺序发票编号的计数器表(法律要求)。值得一提的是,OrderService create方法并不总是由控制器调用,而是通过crobjob/queue系统调用。我的问题是关于创建新订单的用例: class OrderService { async createNewOrder(orderDt
订单
和发票
,以及一个用于顺序发票编号的计数器表(法律要求)。值得一提的是,OrderService create方法并不总是由控制器调用,而是通过crobjob/queue系统调用。我的问题是关于创建新订单的用例:
class OrderService {
async createNewOrder(orderDto) {
const order = new Order();
order.customer = orderDto.customer;
order.items = orderDto.items;
const invoice = await this.InvoiceService.createInvoice(orderDto.items);
order.invoice = invoice;
await order.persistAndFlush();
return order
}
}
class InvoiceService {
async create(items): Invoice {
const invoice = new Invoice();
invoice.number = await this.InvoiceNumberService.getNextInSequence();
// the next two lines are external apis, if they throw, the whole transaction should roll back
const pdf = await this.PdfCreator.createPdf(invoice);
const upload = await s3Api.uplpad(pdf);
return invoice;
}
}
class InvoiceNumberService {
async getNextInSequence(): number {
return await db.collection("counter").findOneAndUpdate({ type: "INVOICE" }, { $inc: { value: 1 } });
}
}
使用所有后续服务调用创建新订单的整个用例应该发生在一个Mikro Orm事务中。因此,如果OrderService.createNewOrder()或随后调用的某个方法中抛出任何内容,则应回滚整个事务
我将从坏消息开始,mongodb事务在MikroORM中还不受支持(尽管它们可能在几周内到达,已经实现了PoC)。您可以在此处订阅更新: 但让我回答其余的问题,因为它将适用于: 您可以使用
const collection=(em作为EntityManager).getConnection().getCollection('counter')
从内部mongo连接实例获取集合。您还可以使用orm.em.getTransactionContext()
获取当前的事务上下文(当前仅在sql驱动程序中实现,但将来可能会在mongo中返回会话
对象)
还要注意的是,在mongo驱动程序中,默认情况下不会启用隐式事务(尽管它是可配置的),因此您需要通过em.transactional(…)
使用显式事务划分
RequestContext
助手自动工作。只需将其注册为中间件(在nestjs orm适配器中自动完成),然后在共享上下文的域中运行请求处理程序(路由/端点/控制器方法)。由于这一点,DI中的所有服务都可以共享存储库的单实例,但它们会自动从域中选择正确的上下文
您基本上拥有这个自动请求上下文,然后您可以通过em.transactional(…)
手动创建新的(嵌套的)上下文
我将从坏消息开始,mongodb事务在MikroORM中还不受支持(尽管它们可能会在几周内到达,已经实现了PoC)。您可以在此处订阅更新: 但让我回答其余的问题,因为它将适用于: 您可以使用
const collection=(em作为EntityManager).getConnection().getCollection('counter')
从内部mongo连接实例获取集合。您还可以使用orm.em.getTransactionContext()
获取当前的事务上下文(当前仅在sql驱动程序中实现,但将来可能会在mongo中返回会话
对象)
还要注意的是,在mongo驱动程序中,默认情况下不会启用隐式事务(尽管它是可配置的),因此您需要通过em.transactional(…)
使用显式事务划分
RequestContext
助手自动工作。只需将其注册为中间件(在nestjs orm适配器中自动完成),然后在共享上下文的域中运行请求处理程序(路由/端点/控制器方法)。由于这一点,DI中的所有服务都可以共享存储库的单实例,但它们会自动从域中选择正确的上下文
您基本上拥有这个自动请求上下文,然后您可以通过em.transactional(…)
手动创建新的(嵌套的)上下文
哇,谢谢。关于请求上下文:我的服务方法不是由控制器调用的,而是通过cronjob。。。因此没有调用控制器,因此没有中间件。所以我假设,每当通过CronJob调用OrdersService.createNewOrder()时,我的服务将始终使用相同的IdentityMap…因此IdentityMap将无限增长。不是真的,如果您cron始终调用MikroORM.init(),那么您总是有新的上下文。您还可以使用em.fork()手动创建一个。哇,谢谢。关于请求上下文:我的服务方法不是由控制器调用的,而是通过cronjob。。。因此没有调用控制器,因此没有中间件。所以我假设,每当通过CronJob调用OrdersService.createNewOrder()时,我的服务将始终使用相同的IdentityMap…因此IdentityMap将无限增长。不是真的,如果您cron始终调用MikroORM.init(),那么您总是有新的上下文。您还可以使用em.fork()手动创建一个。