如何防止此事件请求1:我获取文档A并更改某些内容请求2:我获取文档A并更改其他内容请求1:我保存文档A请求2:我保存文档A现在请求1的更改将被覆盖如何防止此事件
如果这个请求被频繁地调用,则更改不会被保存,这只是一个示例,我在应用程序中有更复杂的代码,
exports.readInfo = async (req, res, n) => {
const user = req.user;
const data = req.data;
const doc = await Doc.findOne({ _id: new ObjectId(data._id) });
//changes from request 1 might be saved now
doc.infos[data.key][data.skey][data.i].read.push(user._id.toString());
doc.markModified("infos." + data.key + "." + data.skey + "." + data.i);
await doc.save();
return res.end("success");
};
字符串
2条答案
按热度按时间7dl7o3gd1#
这更像是一个系统设计问题,因为JavaScript并没有内置任何东西(我知道)来处理它。
您的问题基本上是一个竞态条件,如下所述:https://stackoverflow.com/a/34550/8346513
简而言之,两个进程试图同时修改同一段数据,哪一个进程获胜有点随意,很难确定。
有几种方法可以处理这个问题。
在资源上使用互斥或锁。
这是防止此类问题发生的一种简单方法。它看起来像这样:
字符串
这是相对便宜的,因为JavaScript是单线程的,在这种情况下工作得很好。但是它也有一些缺点,即你必须在每个可能使用这个资源的地方都有相同的锁(这可能是很多样板),而且如果你的进程在工作过程中崩溃,它永远不会释放锁,这可能会导致你的应用程序死锁。
使用历史队列处理更改
这与上面的例子类似,在上面的例子中,一次只能修改一个东西。但是现在不是像这样把那个东西放在你的API中,你会有一个通过以下步骤运行的系统:
这可以确保只有一个地方写入数据,并且需要的样板文件要少得多。然而,这也有一些问题。即设置要复杂得多,并且所有操作都将使用过时的数据运行。
你也可以使用一个更简单的内存缓存层来保存数据的实时副本。如果你修改了它,然后将更改的内容排队,那么你就可以更新数据而不需要执行code-c,这意味着你的请求不再需要阻塞,而是定期将数据发送到数据库。这也很复杂,但确实解决了上面的一些问题,而且如果程序崩溃,也会冒着没有完全写入所有数据的风险。
结论
如你所见,这不是一件容易解决的事情。我推荐使用简单的互斥锁,因为对于一个不需要完美的应用程序来说,它可能是最容易启动和运行的东西。但是如果你正在构建一个企业级应用程序,那么研究一下其他方法或其他东西可能会很好(可能是现成的解决方案),以确保尽可能多的基地覆盖。
8e2ybdfx2#
你可以使用这个解决方案
字符串
但在状态为锁定时不返回任何内容
为了更好的解决方案,你需要在应用层实现锁功能(我认为Mongodb没有实现这一点,但Postgres做到了)
简单的例子
型
结果:
型