【问题标题】:Mongo transactions and updatesMongodb 事务和更新
【发布时间】:2015-04-23 06:12:49
【问题描述】:

如果我有一个环境,其中同一客户端的多个实例连接到 MongoDB 服务器,并且我想要一个简单的锁定机制来确保短时间内单个客户端访问,我可以安全地使用自己的锁定对象吗?

假设我有一个带有 lockState 的对象,可以“锁定”或“解锁”,计划是每个人在做“事情”之前检查它是否“解锁”。要锁定系统,我说:

db.collection.update( { "lockState": "unlocked" }, { "lockState": "locked" })

(又名UPDATE lockObj SET lockState = 'locked' WHERE lockState = 'unlocked'

如果两个客户端同时尝试锁定系统,是否有可能两个客户端最终都认为他们“拥有锁定”?

  • 两个客户端都通过更新的查询参数找到记录
  • 客户端 1 更新记录(这是一个原子操作)
    • 更新返回成功
  • 客户端 2 更新文档(在客户端 1 修改之前已经找到它)
    • 更新返回成功

我意识到这可能是一个非常人为的案例,很难重现,但有可能还是 mongo 以某种方式使客户端 2 的更新失败?

替代方法
使用插入而不是更新。 insert 是原子的,如果文档已经存在就会失败。

锁定系统:db.locks.insert({someId: 27, state: “locked”})。 如果插入成功 - 我已经获得了锁,并且由于更新是原子的,所以没有其他人可以拥有它。 如果插入失败 - 其他人必须拥有锁。

【问题讨论】:

  • 等等,你是不是故意将你的数据库从多线程向下钻取到单线程?这就是第一段所说的......

标签: mongodb


【解决方案1】:

如果两个客户端同时尝试锁定系统,是否有可能两个客户端最终都认为他们“拥有锁定”?

不,一次只有一个客户端写入锁定空间(全局、数据库、集合或文档,具体取决于您的版本和配置),并且对该锁定空间的操作是顺序的,并且一个或另一个(读取或写入,不是两者)每个文档,这样其他连接就不会错误地拾取处于中间状态的文档并认为它没有被另一个客户端锁定。

对单个文档的所有操作都是原子操作,无论是更新还是插入。

【讨论】:

  • 感谢@Sammaye - 将其缩小为最简单的形式:“更新(查询+修改)是原子的”?
  • @John3136 实际上,对于每个文档,多文档更新不会覆盖整个更新,而是会覆盖它通过的每个文档
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-07-01
  • 1970-01-01
  • 2022-08-05
  • 2023-03-29
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多