gpt4 book ai didi

javascript - 使用 mongoose 中间件删除依赖文档时的并发问题

转载 作者:IT老高 更新时间:2023-10-28 12:31:22 28 4
gpt4 key购买 nike

假设我们有一个简单的应用程序,用户可以在其中创建产品并对其进行评论。产品和评论的架构可以是:

var productSchema = new mongoose.Schema({
author_id: ObjectId,
description: String
});

var commentSchema = new mongoose.Schema({
product_id: ObjectId,
author_id: ObjectId,
message: String
});

我们希望确保每条评论都指向现有产品。这可以通过 mongoose pre save hook 轻松完成:

commentSchema.pre("save", function(next) {
Product.count({ _id: this.product_id }, function(err, count) {
if (err || !count) {
next(new Error("Could not find product"));
} else {
next();
}
});
});

此外,如果用户删除了产品,我们希望删除对该产品的所有评论。这可以使用 pre remove hook 轻松完成:

productSchema.pre("remove", function(next) {
Comment.remove({ product_id: this._id }, next);
});

但是如果用户 A 删除了一个产品,同时用户 B 对该产品发表了评论呢?

可能会发生以下情况:

Call pre save hook for new comment, and check if product exists
Call pre remove hook for product, and remove all comments
In pre save hook, done checking: product actually exists, call next
Comment saved
In pre remove hook, done removing comments: call next
Product removed

最终结果是我们有一个评论指向一个不存在的产品。

这只是导致这种情况发生的众多情况之一。如何防止这种极端情况?

最佳答案

似乎使用 Mongoose post hooks 而不是 pre hooks 可以解决问题:

commentSchema.post("save", function(comment) {
Product.count({ _id: comment.product_id }, function(err, count) {
if (err || !count) comment.remove();
});
});

productSchema.post("remove", function(product) {
Comment.remove({ product_id: product._id }).exec();
});

让我们通过考虑四种可能的情况(我能想到的)来看看为什么这可以解决问题:

1) Comment gets saved before product is removed
2) Comment gets saved after product is removed but before post remove hook
3) Comment gets saved after product is removed and while post remove hook is
executing
4) Comment gets saved after product is removed and post remove hook executed
------------------------------------------------------------------------
In case 1, after the product is removed, the comment will be removed in the post
remove hook.
In case 2, same, post remove hook will remove the comment.
In case 3, the comment post save hook will successfully remove the comment.
In case 4, same as case 3, post save hook removes the comment.

但是还有一个小问题:如果在产品被移除之后 post remove hook 执行之前发生了一些不好的事情怎么办?说停电或类似的事情。在这种情况下,我们最终会得到引用不存在产品的评论。为了解决这个问题,我们可以在产品上保留 pre remove hook。这保证了仅在删除所有相关评论时才删除产品。然而,正如 OP 所指出的,这不能处理并发问题,这就是我们的 post remove hook 来救援的地方!所以我们两者都需要:

productSchema.pre("remove", function(next) {
var product = this;
Comment.remove({ product_id: product._id }, next);
});

productSchema.post("remove", function(product) {
Comment.remove({ product_id: product._id }).exec();
});

我希望是这样,但我仍然可以想到一个非常遥远的案例:如果在删除产品后保存评论并且 post remove hook 在评论之前执行 怎么办? >post save hook 执行(这将删除评论)灯熄灭!我们最终得到的评论是指不存在的产品!这种情况发生的几率非常低,但仍然......

如果有人能想到更好的并发处理方法,请改进我的答案或自己编写!

关于javascript - 使用 mongoose 中间件删除依赖文档时的并发问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42521550/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com