我这里有一个奇怪的情况 我正在尝试在数组中插入一些写入查询(它们都属于同一事务),并使用 Promise.all(arr) 对整个事务执行/回滚 问题是,如果我的代码抛出错误并且我在调用 Promise.all() 之前中止事务,则承诺数组中要完成的操作将被提交!但是,如果我的代码在调用 Promise.all() 后抛出错误,文档将按预期恢复到原始状态。 即使事务仅仅因为我在调用 Promise.all() 之前抛出异常而中止,如何避免提交对文档的更改。
这是代码片段
module.exports.updateVariantStock = async (req, res, next) => {
const session = await mongoose.startSession();
try {
session.startTransaction();
const opts = { session };
const { newStock } = req.body;
const { variant } = req.mydata;
const promises = [];
variant.stock = Number(variant.stock) + Number(newStock);
const variantPromise = variant.save(opts);
promises.push(variantPromise);
const stockLogElement = new VariantStockLogElement({
// Data to insert
});
const newStockLogContainerPromise = stockLogElement.save(opts);
promises.push(newStockLogContainerPromise);
throw new Error("A test error"); // If error is thrown here, changes are commited
await Promise.all(promises);
throw new Error("A test error"); // If error is thrown here, changes are rolled-back
await session.commitTransaction();
return res.status(200).json({ success: "Stock is updated." });
} catch (err) {
await session.abortTransaction();
next(err);
} finally {
session.endSession();
}
};
请注意,如果我在抛出此错误之前运行任何数据库查询(与事务无关),则更改将回滚。但我收到这个错误
UnhandledPromiseRejectionWarning: MongoError: Transaction with { txnNumber: 1 } has been aborted.
我真的不明白这里发生了什么。
在 MongoDB 中使用 Promise.all 进行事务处理时,了解 Promise 的结算顺序非常重要。在代码中,当您在调用 Promise.all(promises) 之前抛出错误时,数组中的 Promise 可能已经开始执行,并且 MongoDB 可能会将这些更改视为事务外部的单独操作。但是,如果在调用 Promise.all(promises) 后抛出错误,则操作将捆绑到同一事务中。为了确保在调用 Promise.all 之前不会执行数组中的 Promise,您可以将 throw new Error("A test error") 行移到 Promise.all(promises) 之后。你可以考虑做这样的事情,
// Execute promises within the transaction
const promiseResult = await Promise.all(promises);
// Check if any promise rejected
const hasRejectedPromise = promiseResult.some(p => p instanceof Error || p instanceof mongoose.Error);
if (hasRejectedPromise) {
throw new Error("A test error"); // If error is thrown here, changes are rolled-back
}
await session.commitTransaction();
但由于某种原因,您的目标是在单个 Promise 抛出错误时立即中止事务,您可以通过删除 Promise.all 并使用 try...catch 块单独处理每个 Promise 来实现此目的。如果任何 Promise 抛出错误,您可以立即中止事务并处理错误。考虑这样的事情,
variant.stock = Number(variant.stock) + Number(newStock);
const variantPromise = variant.save(opts);
try {
await variantPromise; // Handle the promise individually
} catch (error) {
// If an error occurs, immediately abort the transaction
await session.abortTransaction();
throw error;
}
const stockLogElement = new VariantStockLogElement({
// Data to insert
});
const newStockLogContainerPromise = stockLogElement.save(opts);
try {
await newStockLogContainerPromise; // Handle the promise individually
} catch (error) {
// If an error occurs, immediately abort the transaction
await session.abortTransaction();
throw error;
}
await session.commitTransaction();
// .... Continue with the rest of your code ...