MongoDB 与@NestJs/mongoose 的交易无效
MongoDB transaction with @NestJs/mongoose not working
我真的需要你的帮助。我的 MongoDB 交易与 @NestJs/mongoose 不工作...当我的条带支付失败回滚不工作...不过,我的订单收集保存了数据...我该如何解决这个问题.. ?
async create(orderData: CreateOrderServiceDto): Promise<any> {
const session = await this.connection.startSession();
session.startTransaction();
try {
const createOrder = new this.orderModel(orderData);
const order = await createOrder.save();
await this.stripeService.charge(
orderData.amount,
orderData.paymentMethodId,
orderData.stripeCustomerId,
);
await session.commitTransaction();
return order;
} catch (error) {
await session.abortTransaction();
throw error;
} finally {
await session.endSession();
}
}
我有同样的问题,我在 github 上发现:Mongo DB Transactions With Mongoose & Nestjs
所以我认为,根据这个问题,你必须调用模型的 create
方法,就像这样:
const order = await this.orderModel.create(orderData, { session });
如您所见,Model.create
方法有一个以 SaveOptions
作为参数的重载:
create(docs: (AnyKeys<T> | AnyObject)[], options?: SaveOptions): Promise<HydratedDocument<T, TMethodsAndOverrides, TVirtuals>[]>;
它需要一个可选的 SaveOptions
参数,该参数可以包含会话:
interface SaveOptions {
checkKeys?: boolean;
j?: boolean;
safe?: boolean | WriteConcern;
session?: ClientSession | null;
timestamps?: boolean;
validateBeforeSave?: boolean;
validateModifiedOnly?: boolean;
w?: number | string;
wtimeout?: number;
}
请注意 Model.save()
也可以带一个 SaveOptions
参数。
所以你也可以这样做:
const createOrder = new this.orderModel(orderData);
const order = await createOrder.save({ session });
再远一点...
因为我做了很多需要交易的事情,所以我想出了这个助手来避免很多代码重复:
import { InternalServerErrorException } from "@nestjs/common"
import { Connection, ClientSession } from "mongoose"
export const mongooseTransactionHandler = async <T = any>(
method: (session: ClientSession) => Promise<T>,
onError: (error: any) => any,
connection: Connection, session?: ClientSession
): Promise<T> => {
const isSessionFurnished = session === undefined ? false : true
if (isSessionFurnished === false) {
session = await connection.startSession()
session.startTransaction()
}
let error
let result: T
try {
result = await method(session)
if (isSessionFurnished === false) {
await session.commitTransaction()
}
} catch (err) {
error = err
if (isSessionFurnished === false) {
await session.abortTransaction()
}
} finally {
if (isSessionFurnished === false) {
await session.endSession()
}
if (error) {
onError(error)
}
return result
}
}
详情
可选参数 session
是为了防止您正在执行嵌套嵌套事务。
这就是为什么我检查是否提供了会话。如果是,则意味着我们处于嵌套事务中。因此,我们将让主事务提交、中止并结束会话。
例子
例如:你删除了一个User
模特,然后用户头像是一个File
模特
/** UserService **/
async deleteById(id: string): Promise<void> {
const transactionHandlerMethod = async (session: ClientSession): Promise<void> => {
const user = await this.userModel.findOneAndDelete(id, { session })
await this.fileService.deleteById(user.avatar._id.toString(), session)
}
const onError = (error: any) => {
throw error
}
await mongooseTransactionHandler<void>(
transactionHandlerMethod,
onError,
this.connection
)
}
/** FileService **/
async deleteById(id: string, session?: ClientSession): Promise<void> {
const transactionHandlerMethod = async (session: ClientSession): Promise<void> => {
await this.fileModel.findOneAndRemove(id, { session })
}
const onError = (error: any) => {
throw error
}
await mongooseTransactionHandler<void>(
transactionHandlerMethod,
onError,
this.connection,
session
)
}
所以,简而言之:
你可以这样使用它:
async create(orderData: CreateOrderServiceDto): Promise<any> {
const transactionHandlerMethod = async (session: ClientSession): Promise<Order> => {
const createOrder = new this.orderModel(orderData);
const order = await createOrder.save({ session });
await this.stripeService.charge(
orderData.amount,
orderData.paymentMethodId,
orderData.stripeCustomerId,
);
return order
}
const onError = (error: any): void => {
throw error
}
const order = await mongooseTransactionHandler<Order>(
transactionHandlerMethod,
onError,
this.connection
)
return order
}
希望对您有所帮助。
我真的需要你的帮助。我的 MongoDB 交易与 @NestJs/mongoose 不工作...当我的条带支付失败回滚不工作...不过,我的订单收集保存了数据...我该如何解决这个问题.. ?
async create(orderData: CreateOrderServiceDto): Promise<any> {
const session = await this.connection.startSession();
session.startTransaction();
try {
const createOrder = new this.orderModel(orderData);
const order = await createOrder.save();
await this.stripeService.charge(
orderData.amount,
orderData.paymentMethodId,
orderData.stripeCustomerId,
);
await session.commitTransaction();
return order;
} catch (error) {
await session.abortTransaction();
throw error;
} finally {
await session.endSession();
}
}
我有同样的问题,我在 github 上发现:Mongo DB Transactions With Mongoose & Nestjs
所以我认为,根据这个问题,你必须调用模型的 create
方法,就像这样:
const order = await this.orderModel.create(orderData, { session });
如您所见,Model.create
方法有一个以 SaveOptions
作为参数的重载:
create(docs: (AnyKeys<T> | AnyObject)[], options?: SaveOptions): Promise<HydratedDocument<T, TMethodsAndOverrides, TVirtuals>[]>;
它需要一个可选的 SaveOptions
参数,该参数可以包含会话:
interface SaveOptions {
checkKeys?: boolean;
j?: boolean;
safe?: boolean | WriteConcern;
session?: ClientSession | null;
timestamps?: boolean;
validateBeforeSave?: boolean;
validateModifiedOnly?: boolean;
w?: number | string;
wtimeout?: number;
}
请注意 Model.save()
也可以带一个 SaveOptions
参数。
所以你也可以这样做:
const createOrder = new this.orderModel(orderData);
const order = await createOrder.save({ session });
再远一点...
因为我做了很多需要交易的事情,所以我想出了这个助手来避免很多代码重复:
import { InternalServerErrorException } from "@nestjs/common"
import { Connection, ClientSession } from "mongoose"
export const mongooseTransactionHandler = async <T = any>(
method: (session: ClientSession) => Promise<T>,
onError: (error: any) => any,
connection: Connection, session?: ClientSession
): Promise<T> => {
const isSessionFurnished = session === undefined ? false : true
if (isSessionFurnished === false) {
session = await connection.startSession()
session.startTransaction()
}
let error
let result: T
try {
result = await method(session)
if (isSessionFurnished === false) {
await session.commitTransaction()
}
} catch (err) {
error = err
if (isSessionFurnished === false) {
await session.abortTransaction()
}
} finally {
if (isSessionFurnished === false) {
await session.endSession()
}
if (error) {
onError(error)
}
return result
}
}
详情
可选参数 session
是为了防止您正在执行嵌套嵌套事务。
这就是为什么我检查是否提供了会话。如果是,则意味着我们处于嵌套事务中。因此,我们将让主事务提交、中止并结束会话。
例子
例如:你删除了一个User
模特,然后用户头像是一个File
模特
/** UserService **/
async deleteById(id: string): Promise<void> {
const transactionHandlerMethod = async (session: ClientSession): Promise<void> => {
const user = await this.userModel.findOneAndDelete(id, { session })
await this.fileService.deleteById(user.avatar._id.toString(), session)
}
const onError = (error: any) => {
throw error
}
await mongooseTransactionHandler<void>(
transactionHandlerMethod,
onError,
this.connection
)
}
/** FileService **/
async deleteById(id: string, session?: ClientSession): Promise<void> {
const transactionHandlerMethod = async (session: ClientSession): Promise<void> => {
await this.fileModel.findOneAndRemove(id, { session })
}
const onError = (error: any) => {
throw error
}
await mongooseTransactionHandler<void>(
transactionHandlerMethod,
onError,
this.connection,
session
)
}
所以,简而言之:
你可以这样使用它:
async create(orderData: CreateOrderServiceDto): Promise<any> {
const transactionHandlerMethod = async (session: ClientSession): Promise<Order> => {
const createOrder = new this.orderModel(orderData);
const order = await createOrder.save({ session });
await this.stripeService.charge(
orderData.amount,
orderData.paymentMethodId,
orderData.stripeCustomerId,
);
return order
}
const onError = (error: any): void => {
throw error
}
const order = await mongooseTransactionHandler<Order>(
transactionHandlerMethod,
onError,
this.connection
)
return order
}
希望对您有所帮助。