Mongodb 简明教程

MongoDB - Atomic Operations

Model Data for Atomic Operations

推荐的原子性维护方法是将所有相关信息保存在使用 embedded documents 的单文档中,该文档经常一起更新。这将确保针对单文档的所有更新都是原子的。

假设我们已创建一个名为 productDetails 的集合,并按如下所示在集合中插入文档:

>db.createCollection("products")
{ "ok" : 1 }
> db.productDetails.insert(
	{
		"_id":1,
		"product_name": "Samsung S3",
		"category": "mobiles",
		"product_total": 5,
		"product_available": 3,
		"product_bought_by": [
			{
				"customer": "john",
				"date": "7-Jan-2014"
			},
			{
				"customer": "mark",
				"date": "8-Jan-2014"
			}
		]
	}
)
WriteResult({ "nInserted" : 1 })
>

在此文档中,我们已将购买该产品的客户信息嵌入到 product_bought_by 域中。现在,每当有新客户购买该产品时,我们首先会使用 product_available 域检查该产品是否仍然可用。如果可用,我们将减小 product_available 域的值,并在 product_bought_by 域中插入新客户的嵌入式文档。我们将为此功能使用 findAndModify 命令,因为它在同一执行步骤中搜索并更新文档。

>db.products.findAndModify({
   query:{_id:2,product_available:{$gt:0}},
   update:{
      $inc:{product_available:-1},
      $push:{product_bought_by:{customer:"rob",date:"9-Jan-2014"}}
   }
})

我们的嵌入式文档方法和使用 findAndModify 查询可确保仅在产品可用时才会更新产品购买信息。而且,这项事务的全部内容都在同一查询中,是原子的。

与之相反,考虑一下可能将产品可用性和关于谁已购买该产品的信息分开保存的情况。在这种情况下,我们将首先使用第一个查询检查产品是否可用。然后,在第二个查询中,我们将更新购买信息。然而,在执行这两个查询的过程中,另一些用户可能已购买该产品,而产品已不再可用。在不知道这种情况之下,我们的第二个查询将根据第一个查询的结果更新购买信息。这将使数据库不一致,因为我们已销售了不可用的产品。