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