MongoDB 并不支持多文檔原子事務(multi-document atomic transactions)。但它提供了針對單個文檔的原子操作。假如一個文檔包含數(shù)百個字段,則 update 語句將更新所有的字段,或者一個也不更新,從而維持了文檔級的原子性。
維持原子性的建議方法是利用內(nèi)嵌文檔(embedded document)將所有經(jīng)常更新的相關(guān)信息都保存在一個文檔中。這能確保所有針對單一文檔的更新具有原子性。
考慮下列關(guān)于產(chǎn)品的文檔:
{
"_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"
}
]
}
在這個文檔中,將購買產(chǎn)品的顧客的信息內(nèi)嵌在 product_bought_by 字段中。無論何時,只要新顧客購買產(chǎn)品,我們就能使用 product_available 字段查看產(chǎn)品是否還有足夠的數(shù)量。如果產(chǎn)品還有,就減少 product_available 字段值,并且將新顧客的內(nèi)嵌文檔插入到 product_bought_by 字段中。使用 findAndModify 命令來實現(xiàn)該功能,因為它能同時搜索并更新文檔。
>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"}}
}
})
上述內(nèi)嵌文檔并使用 findAndModify 查詢的方法確保了,只有當產(chǎn)品還有足夠數(shù)量時,才更新產(chǎn)品購買信息。在整個過程中,同一查詢中的事務是原子性的。
與之相反的情況是,我們可能會想分別保持產(chǎn)品可用性與購買產(chǎn)品的顧客信息。在這種情況下,我們會首先使用第一個查詢來檢查產(chǎn)品是否夠用。然后在第二個查詢中更新購買信息。但在這兩個查詢的執(zhí)行過程之間,其他一些顧客也可能會購買了產(chǎn)品,從而使產(chǎn)品變得不夠用了。由于沒有了解到這種情況,我們的第二個查詢根據(jù)第一個查詢的結(jié)果進行了更新。這將造成數(shù)據(jù)庫的不一致性。