mongodb 更新查询是原子的吗?

ita*_*ied 5 concurrency multithreading updates mongodb

mongodb写入和更新操作是原子的,如他们的文档中所述

但是在使用查询时它也是原子的吗?

例如:

db.collection.update( { id : 1 , count : 0 } , { $inc : { count : 1 } } )
Run Code Online (Sandbox Code Playgroud)

如果我在多线程环境中执行此操作,是否有可能在某个时刻count文档中id等于 1 的值会大于 1?

kev*_*adi 7

对单个文档的任何修改都是原子的。

使用您的示例,假设有两个线程尝试使用相同的查询更新该文档:

Thread A: db.collection.update({_id: 1, count: 0}, {$inc: {count: 1}})
Thread B: db.collection.update({_id: 1, count: 0}, {$inc: {count: 1}})
Run Code Online (Sandbox Code Playgroud)

包含文档的集合:

collection: {_id: 1, count: 0}
Run Code Online (Sandbox Code Playgroud)

如果 threadA设法在 thread 之前更新文档B,则集合将包含:

collection: {_id: 1, count: 1}
Run Code Online (Sandbox Code Playgroud)

ThreadB将搜索匹配的文档,_id:1, count:0但由于该文档已被 thread 修改,因此 threadA中的更新B将不会继续(因为对于 threadB而言,该文档不再“存在” )。

换句话说,线程A会返回nMatched: 1, nModified: 1,线程B也会返回nMatched: 0, nModified: 0

为了具体回答您的问题,{_id: 1, count: 2}不会存在文档存在的情况。

  • 不,`update` 命令将确保在应用更新之前更新条件为真。此外,如果两个线程碰巧同时尝试写入同一个文档,其中一个将得到 `WriteConflict` 异常并透明地重试。此重试将不会成功,因为不再满足更新条件。 (4认同)
  • 这个答案是正确的。“单个文档的更新操作是原子的”意味着选择和修改作为原子操作发生。这在书《MongoDB in Action》第二版,第 7 章更新、原子操作和删除,第 12 页中提到。168_(第一行)。只是为了提供有关更新操作的更多信息,在 upsert=true 的情况下,我们需要按照 [update-with-unique-indexes](https://docs.mongodb.com/manual/reference/method/db 中提到的那样小心.collection.update/#update-with-unique-indexes) (2认同)