【发布时间】:2017-07-01 21:01:46
【问题描述】:
我对从数据库中获取文档、根据一些外部条件运行一些计算、更新文档的一个字段然后保存文档的场景感兴趣,所有这些都在一个系统中可能有并发线程访问数据库。
为了更容易理解,这里有一个非常简单的例子。假设我有以下文件:
{
...
items_average: 1234,
last_10_items: [10,2187,2133, ...]
...
}
假设有一个新项目(X)进来,需要做五件事:
- 从数据库中读取文档
- 删除
last_10_items中的第一个(最旧的)项目 - 将 X 添加到数组的末尾
- 重新计算平均值*并将其保存在
items_average。 - 将文档写入数据库
* 注意:选择平均计算作为一个非常简单的例子,但问题应该考虑到基于文档中现有数据和新数据的更复杂的操作(即@987654325 无法解决的问题@运算符)
这在单线程系统中当然很容易实现,但在并发系统中,如果有 2 个线程想要遵循上述步骤,则可能会出现不一致,因为两者都会更新 last_10_items 和 items_average 值不考虑和/或覆盖并发更改。
那么,我的问题是如何处理这种情况?有没有办法检查或响应基础文档在步骤 1 和 5 之间发生更改的事实?是否存在诸如来自 redis 的 WATCH 或来自关系数据库的“并发修改错误”之类的东西?
谢谢
【问题讨论】:
-
这不会发生,因为单个文档的写入和读取不会同时发生
-
我认为,在阅读了您的整个问题后,您的意思是来自客户端的另一个连接的修改,这需要在查找和更新之间进行复杂的计算周期。在这种情况下,您将使用版本字段来防止过时的数据过滤到数据库中
-
是的,是后一种情况。您的意思是在文档上有一个
version字段或updated_at字段,然后使用db.foo.update({version=last_known_version}, {...stuff to update...})之类的东西并检查结果?我认为这可以工作,虽然感觉有点 hacky。我希望 MongoDB 内部机制能够更好地检测并发修改。 -
最好用作版本字段,这里有一个很好的教程:askasya.com/post/trackversions
-
请记住,这也是 SQL 技术人员所做的事情,但在幕后,他们会跟踪版本,这就是他们检测过时数据的方式,在 MongoDB 的情况下,您只需要自己做
标签: mongodb database-design concurrency nosql