MongoDB 原子操作
原子操作的数据模型
推荐保持原子性的方法是使用嵌入式文档,将所有经常更新的相关信息一起放在单个文档中。这样可以确保对单个文档的所有更新都是原子性的。 假设我们已经创建了一个名为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查询的方法,确保只有在产品可用的情况下才会更新产品购买信息。而且,整个事务都在同一个查询中进行,是原子操作。
相比之下,考虑一种情况,我们可能分别保存了产品的可用性和购买产品的信息。在这种情况下,我们将首先使用第一个查询检查产品是否可用。然后在第二个查询中,我们将更新购买信息。然而,在这两个查询的执行之间,可能有其他用户购买了该产品,导致该产品已不再可用。在不知道这一点的情况下,我们的第二个查询将基于第一个查询的结果更新购买信息。这将使数据库不一致,因为我们售出了一种不可用的产品。