【问题标题】:Atomicity and CAS operations in MongoDBMongoDB中的原子性和CAS操作
【发布时间】:2013-05-07 13:54:35
【问题描述】:

目前我正在尝试了解如何在 mongodb 中正确实现 CAS 操作以支持乐观锁定。我发现mongodb 中的更新是原子的,但我不确定这意味着什么(只有文档重写是原子的或所有更新周期,包括搜索相应的文档及其重写,是原子的?)。让我们考虑以下示例。

  1. 某些文档存在于某个集合中,其 _id 值设置为 123,属性 cas_val 设置为 10。
  2. 第一个客户端想要将文档的cas_val 更新为_id 等于123 到11。
  3. 第二个客户端想要将文档的cas_val 更新为_id 等于123 到11。
  4. 两个客户端同时操作,操作可以交错。

那么,如果没有对带有_id 123 的文档执行其他更新,both 操作是否可能成功?

附: mongodb 中是否有一些针对乐观锁定场景的内置技术?

【问题讨论】:

  • 单独使用 $inc 将不允许您实现乐观锁定,因为您可能会更改其他字段。

标签: mongodb


【解决方案1】:

乐观锁定的正确技术是使用详细描述的“如果当前更新”in MongoDB docs

此技术的关键在于更新条件不能简单地为{_id:123},而必须为{_id:123, cas_val: 10},并且更新子句将$set 适当的字段,包括将cas_val 增加到11。

现在“输掉”比赛并第二次到达的线程将找不到要更新的匹配文档,并且需要通过重新获取文档(现在使用 cas_val 11)“重试”并重试。判断更新是否成功的方法是检查 writeConcern 结构(它将指示“n”中有多少记录受到影响,以及“updatedExisting”字段中是否更新了现有记录)。

【讨论】:

  • 感谢您提供有用的链接。这正是我打算做的。
  • @gkuzmin 虽然另一个答案肯定也是相关的,但我认为您应该将此标记为“已接受为最佳答案”?
  • 是的,现在这个答案更有意义了。
【解决方案2】:

如果您使用具有正确运算符的原子更新,则无需获取文档然后对其进行更新,因此更新不会交错(至少数据集仍然是一致的)。顺便说一句,您似乎想要一个$inc operator

【讨论】:

  • 我肯定想获取文档,然后以乐观锁定的方式更新它们。而且似乎不可能使用$inc 运算符构建乐观锁定。至少我无法理解如何使用$inc。顺便说一句,您对示例有何看法?
  • 在这种情况下,您可以考虑添加一个version 字段,这是一个增量。您的update 操作将匹配_id: 123version: x,因此如果版本同时增加,则不会更新此文档。要检查文档是否已更新,您可以检查getlasterror 消息的n 编号(请参阅stackoverflow.com/questions/4596846/…
  • 这正是我想知道的!谢谢!附言在我的示例中,cas_value 扮演 version 字段角色。
  • 那么这不是正确的顺序 - 一个线程将其更新为 11,另一个线程将其更新为 12,但第二个线程将覆盖第一个线程所做的其他更新。
猜你喜欢
  • 1970-01-01
  • 2017-11-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-10-15
  • 2021-05-13
  • 1970-01-01
相关资源
最近更新 更多