我有 2 个服务,每个服务都有自己的事务块,如下所示:
function tranA() {
const session = await this.connection.startSession();
try {
session.startTransaction();
// Query with the session
await session.commitTransaction();
} catch {
await session.abortTransaction();
} finally {
await session.endSession();
}
}
在一个控制器中,我必须调用这两个服务,并确保它们使用 相同的交易,即相同的
session
。我应该如何处理这个问题?
到目前为止我唯一的想法是将查询移动到单独的函数中,然后传递
session
向下,像这样:
function tranA() {
const session = await this.connection.startSession();
try {
session.startTransaction();
this.A(session)
await session.commitTransaction();
} ...
}
function A(session) {
// Query with the session
}
然后在控制器中,我创建自己的
session
,然后调用服务。
这种方法最大的问题是方法名称的重复。现在 许多方法有 2 个版本,一种带有外部会话,一种带有自己的会话 会议。
您可以将会话设置为可选参数,并有条件地在服务中创建它吗?
我对Nest不太熟悉,似乎它有一个自定义装饰器的选项,但是在vanila节点中,事务装饰器可以这样实现:
async function inTransaction(f, session=null) {
let result;
if (!session) {
const newSession = await this.connection.startSession();
try {
newSession.startTransaction();
result = await f(newSession);
await newSession.commitTransaction();
} catch (error) {
console.log("An error occurred during the transaction:" + error);
await newSession.abortTransaction();
} finally {
await newSession.endSession();
}
} else {
result = await f(session);
}
return result;
async function A(arg1, arg2, sessionFromUpstream=null) {
return inTransaction( session => {
// body of the function A, for the sake of demo:
return arg1 + arg2;
}, sessionFromUpstream);
}
这样,
inTransaction
装饰器将创建一个会话,启动事务,执行函数体,完成事务并关闭会话。如果会话是从上游传递的,例如控制器,事务管理应该在那里处理,并且函数A
将只使用现有的会话。