在MongoDB中锁定文档,同时允许查询获取非锁定记录

时间:2014-08-12 15:55:22

标签: mongodb locking database

在我们的产品中,我们有一个核心集合,可以从一组分布式工作人员访问。

我希望能够从集合中获取文档,而不会让任何工作人员意外地拿起相同的文档。

到目前为止我为防止重复记录加载而提出的最佳方法如下:

拥有2个具有以下基本结构的独立集合:

core: { _id: '{mongoGeneratedId}', locked: false, lockTimeout: 0}
lock: { _id: null, lockTimeout: 0}

(lockTimeout将有一个TTL索引)

工作人员将运行如下所示的查询:

db.core.findOne({
  $or: [
    {locked: false},
    {lockTimeout < $currentTime}
  ]
})

并会返回一条记录。

要测试记录是否已被其他工作人员抓取并锁定,则会尝试将记录插入锁定中,锁定时间为5分钟,其核心ID与核心表中的ID相同。

如果失败,那么我们知道另一名工作人员将我们推到了帖子中,我们想再次尝试运行查询。如果成功,那么我们更新core以锁定为true并使lockTimeout与lock集合中的lockTimeout相同。

除了增加某种形式稍微复杂的排序以减少2名工人获得相同记录的机会之外我相信这应该有效。

然而,它并不优雅,我觉得应该有一个更好的方法,不要求我创建一个二级集合,只是为了跟踪锁定。

这样的事情存在吗?亲切的问候!

1 个答案:

答案 0 :(得分:3)

尝试使用findAndModify命令。此命令以原子方式更新文档并返回文档(默认预置,可选择更新后)。您可以使用原子更新来锁定文档:

> db.queue.insert({ "x" : 1, "locked" : false })
> db.queue.findAndModify({
    "query" : { "locked" : false }, 
    "update" : { "$set" : { "locked" : true } }
})
{ "_id" : ObjectId("53ea6f0ef9b63e0dd3ca1a1f"), "x" : 1, "locked" : false }

您也可以原子地删除文档。查看链接,了解可能有助于类似队列的用例的所有功能,并阅读有关命令行为的更多信息。