我在這里遇到了一個奇怪的情況,我試圖在一個數(shù)組中插入一些寫查詢(所有這些查詢都屬于同一個事務),并使用Promise.all(arr)對整個事務執(zhí)行/回滾。問題是,如果我的代碼拋出錯誤,并且我在調用Promise.all()之前中止了事務,那么promise數(shù)組中的操作to-be-done將被提交!。但是,如果我的代碼在調用Promise.all()后拋出錯誤,文檔將按預期恢復到原始狀態(tài)。如何避免在調用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();
}
};
請注意,如果在拋出此錯誤之前運行任何數(shù)據(jù)庫查詢(與事務無關),則更改為rolled-back。但我犯了這個錯誤
UnhandledPromiseRejectionWarning: MongoError: Transaction with { txnNumber: 1 } has been aborted.
我真的不明白這里發(fā)生了什么。
當將Promise.all與MongoDB中的事務一起使用時,注意承諾的結算順序是很重要的。在您的代碼中,當您在調用Promise.all(promise)之前拋出錯誤時,數(shù)組中的promise可能已經(jīng)開始執(zhí)行,而MongoDB可能會將這些更改視為事務之外的單獨操作。但是,如果在調用Promise.all(promise)后拋出錯誤,則這些操作將綁定到同一事務中。為了確保在調用Promise.all之前不會執(zhí)行數(shù)組中的promise,您可以將換行new Error(“A test Error”)移動到Promise.all(promise)之后。你可以考慮這樣做,
但是,如果出于某種原因,您的目標是在單個promise拋出錯誤時立即中止事務,則可以通過刪除Promise.all并使用try...catch塊單獨處理每個promise來實現(xiàn)這一點。如果任何promise拋出錯誤,您可以立即中止事務并處理錯誤。考慮一下這樣的事情,