javascript - 即使mongodb中的一个事务发生错误,事务也不会中止?
问题描述
router.put('/', async (req, res) => {
try {
const today = new Date();
var month = (today.getMonth()) + 1;
var year = today.getFullYear();
var field = year + "-" + month;
var category = req.body.category;
var date = today.getDate();
const session = mongoose.startSession();
const transactionOptions = {
readPreference: 'primary',
readConcern: { level: 'local' },
writeConcern: { w: 'majority' }
};
const news = await News.findById(req.body.id);
var newsDate = new Date(news.createdAt).getDate();
var newsMonth = new Date(news.createdAt).getMonth() + 1;
var newsYear = new Date(news.createdAt).getFullYear();
// (await session).startTransaction();
// (await Publisher.findOneAndUpdate({ registrationNumber: req.body.registrationNumber }, { $inc: { [`monthlyViews.${field}`]: 1, [`categoriesViews.${category}`]: 1 } })).$session(session);
// if (newsDate == date && newsMonth == month && newsYear == year) {
// (await News.findOneAndUpdate({ _id: req.body.id }, { $inc: { [`views.${field}`]: 1, [`totalViews`]: 1, ['publishedDateViews']: 1 } })).$session(session);
// } else {
// (await News.findOneAndUpdate({ _id: req.body.id }, { $inc: { [`views.${field}`]: 1, [`totalViews`]: 1 } })).$session(session);
// }
// (await session).commitTransaction();
// res.status(200).send({ status: 1 });
const transactionResult = (await session).withTransaction(async () => {
var newsResult;
if (newsDate == date && newsMonth == month && newsYear == year) {
newsResult = (await News.findOneAndUpdate({ _id: req.body.id }, { $inc: { [`views.${field}`]: 1, [`totalViews`]: 1, ['publishedDateViews']: 1 } })).$session(session);
} else {
newsResult = (await News.findOneAndUpdate({ _id: req.body.id }, { $inc: { [`views.${field}`]: 1, [`totalViews`]: 1 } })).$session(session);
}
if (!newsResult) {
return (await session).abortTransaction();
}
const pubresult = (await Publisher.findOneAndUpdate({ registrationNumber: req.body.registrationNumber }, { $inc: { [`monthlyViews.${field}`]: 1, [`categoriesViews.${category}`]: 1 } })).$session(session);
if (!pubresult) {
return (await session).abortTransaction();
}
}, transactionOptions).then(result => { res.status(200).send({ status: 1 }); }).catch(e => {
console.log(e);
res.status(400).send({ status: 0 });
});
} catch (error) {
// (await session).abortTransaction();
console.error(error);
res.status(500).send({ status: 0, message: "Internal Server error" });
} finally {
(await session).endSession();
}
});
每当其中一个事务失败时,它也不会中止事务并且事务被部分提交。例如:当我使用邮递员发送错误的注册号时,Publisher.findoneandUpdate 会返回“TypeError: Cannot read property '$session' of null”,并且该事务应该被中止,但它像 Publisher 行上方的代码一样被部分提交,将其保存在文件。我正在使用 mongodb 地图集
解决方案
我对您的问题的理解是,当您的事务中引发错误时,事务不会中止?
在审查您的代码时,您似乎将 async/await 与 promise 混合在一起,这导致它的可读性降低,而且事情的工作方式也略有不同。
当使用 async/await 时,任何return
语句都会导致 promise 被解析而不是被拒绝,而当使用throw
语句时,promise 将被拒绝而不是被解析。
现在,您可以使用 捕获在回调中引发的任何错误.catch
,但是,如果该方法由于$session
cannot exist on 而引发,则不会调用null
您的方法。(await session).abortTransaction()
但是,您使用 try/catch/finally,两者catch
都finally
不会执行,因为没有引发错误。您已经在回调中发现了任何错误。
相反,纯粹使用 async/await 看看是否有什么不同(请原谅自动格式化的代码):
router.put('/', async (req, res) => {
try {
const today = new Date();
var month = today.getMonth() + 1;
var year = today.getFullYear();
var field = year + '-' + month;
var category = req.body.category;
var date = today.getDate();
const session = await mongoose.startSession(); // await here
const transactionOptions = {
readPreference: 'primary',
readConcern: { level: 'local' },
writeConcern: { w: 'majority' },
};
const news = await News.findById(req.body.id);
var newsDate = new Date(news.createdAt).getDate();
var newsMonth = new Date(news.createdAt).getMonth() + 1;
var newsYear = new Date(news.createdAt).getFullYear();
// (await session).startTransaction();
// (await Publisher.findOneAndUpdate({ registrationNumber: req.body.registrationNumber }, { $inc: { [`monthlyViews.${field}`]: 1, [`categoriesViews.${category}`]: 1 } })).$session(session);
// if (newsDate == date && newsMonth == month && newsYear == year) {
// (await News.findOneAndUpdate({ _id: req.body.id }, { $inc: { [`views.${field}`]: 1, [`totalViews`]: 1, ['publishedDateViews']: 1 } })).$session(session);
// } else {
// (await News.findOneAndUpdate({ _id: req.body.id }, { $inc: { [`views.${field}`]: 1, [`totalViews`]: 1 } })).$session(session);
// }
// (await session).commitTransaction();
// res.status(200).send({ status: 1 });
await session.withTransaction(async () => {
var newsResult;
// if you haven't already, learn about strict equality
if (newsDate == date && newsMonth == month && newsYear == year) {
newsResult = (
await News.findOneAndUpdate(
{ _id: req.body.id },
{
$inc: {
[`views.${field}`]: 1,
[`totalViews`]: 1,
['publishedDateViews']: 1,
},
}
)
).$session(session);
} else {
newsResult = (
await News.findOneAndUpdate(
{ _id: req.body.id },
{ $inc: { [`views.${field}`]: 1, [`totalViews`]: 1 } }
)
).$session(session);
}
if (!newsResult) {
// if not found, catch {} will catch it
throw new Error('news result does not exist');
}
const pubresult = (
await Publisher.findOneAndUpdate(
{ registrationNumber: req.body.registrationNumber },
{
$inc: {
[`monthlyViews.${field}`]: 1,
[`categoriesViews.${category}`]: 1,
},
}
)
).$session(session);
if (!pubresult) {
throw new Error('publisher does not exist');
}
}, transactionOptions);
res.status(200).send({ status: 1 });
} catch (error) {
session.abortTransaction(); // await if async
if (
error.message === 'publisher does not exist' ||
error.message === 'news result does not exist'
) {
res.status(404).send({ status: 0 }); // not found
return;
}
// handle validation errors or whatever you used 400 for
res.status(500).send({ status: 0, message: 'Internal Server error' });
} finally {
session.endSession();
}
});
请注意:我尚未对此进行测试,但是,请尝试一下,看看您的问题是否已得到纠正。如果abortTransaction
和endSession
是异步的,则根据需要使用等待。
推荐阅读
- rust - 不知道如何使用 nom 的 dbg_dmp
- php - 与许多数组相交的最佳方法
- javascript - 视频数组无法在最后一个视频播放时获取下一个按钮以从数组中的第一个视频开始再次播放
- ansible - Ansible 值来自 aws secrets manager
- tizen - Tizen 原生 UI 创建
- windows - 如何在 Windows 批处理上重写这个 bash 命令?
- api - 资源是rest api的强制性条件吗?
- html - BEM 是否有区分状态选择器和子类选择器的约定?
- reactjs - 通过 Axios & React 追加到数组
- python - 将稀疏 NumPy 矩阵加载到 R 中