MongoDB不支持多文檔原子事務(wù)。 但是,它可以為單個文檔提供了原子操作。 因此,如果文檔有一百個字段,則更新語句將更新或不更新所有字段的值,因此在原始級別保持原子性。
維持原子性的推薦方法是將所有相關(guān)信息保存在一起,并使用嵌入式文檔在一個文檔中一起更新。 這將確保單個文檔的所有更新都是原子的。
考慮以下產(chǎn)品文件 -
{
"_id":1,
"product_name": "Huawei P9",
"category": "mobiles",
"product_total": 5,
"product_available": 3,
"product_bought_by": [
{
"customer": "Kobe",
"date": "2017-07-08"
},
{
"customer": "Maxsu",
"date": "2018-07-28"
}
]
}
在上面這個文檔中,已經(jīng)在product_bought_by字段中嵌入了購買產(chǎn)品的客戶的信息。 現(xiàn)在,當(dāng)有新客戶購買產(chǎn)品,首先查看product_available字段檢查產(chǎn)品存貨是否仍然夠用。
如果可用,則減少product_available字段的值,并將新客戶的嵌入式文檔插入到product_bought_by字段中。下面將使用findAndModify命令來執(zhí)行此功能,因為它會以同樣的方式搜索和更新文檔。
>db.products.findAndModify({
query:{_id:2,product_available:{$gt:0}},
update:{
$inc:{product_available:-1},
$push:{product_bought_by:{customer:"Curry",date:"2017-08-08"}}
}
})
嵌入式文檔和使用findAndModify查詢的方法確保產(chǎn)品購買信息僅在產(chǎn)品可用時才更新。 而整個這個事務(wù)在同一個查詢中是原子的。
與此相反的是如果分別保留產(chǎn)品數(shù)量,以及誰購買產(chǎn)品的信息。在這種情況下,我們將首先使用第一個查詢檢查產(chǎn)品是否可用。然后在第二個查詢中更新購買信息。 但是,有可能在執(zhí)行這兩個查詢時(還未執(zhí)行完),其他一些用戶已經(jīng)購買了該產(chǎn)品,并且此產(chǎn)品缺貨了。但是由于程序執(zhí)行過程中并不知曉,第二個查詢將根據(jù)第一個查詢的結(jié)果更新購買信息。這會導(dǎo)致數(shù)據(jù)庫不一致,因為產(chǎn)品已經(jīng)沒有庫存,但是仍然斷續(xù)銷售。