【Mongodb】事務(wù)

概述


  • Mongodb 4.0 支持副本集的多文檔事務(wù)
  • Mongodb 4.2 支持分片集群的多文檔事務(wù)

單個Server是不支持使用事務(wù)烛亦,所以要學(xué)習(xí)事務(wù),需要搭建一個副本集/分片集群

另外需要說明是橘沥,單個文檔操作是原子操作魁袜,而mongodb是文檔型數(shù)據(jù)庫养渴,在單個文檔上爆办,可以嵌入對象/數(shù)組這種格式來維護數(shù)據(jù)的關(guān)系难咕,而不應(yīng)該使用多個集合來維護數(shù)據(jù)之間的關(guān)系。由于mongodb的這種特性距辆,所以單個文檔操作消除了很多需要事務(wù)的需求余佃。

搭建副本集


下面以最簡單的方式搭建一個副本集

  1. 啟動多個mongod實例,這里使用cmd命令啟動
start "Mongodb Service - 27017" /min mongod --port 27017 --replSet "rs0" --dbpath "F:\Database\Mongodb\Data27017" --logpath "F:\Database\Mongodb\Log\mongod.27017.log"
start "Mongodb Service - 27018" /min mongod --port 27018 --replSet "rs0" --dbpath "F:\Database\Mongodb\Data27018" --logpath "F:\Database\Mongodb\Log\mongod.27018.log"

參數(shù)說明

  • replSet : 設(shè)置副本集名稱
  • port : 設(shè)置端口跨算,因為我是單機爆土,所以只能設(shè)置不同端口
  • dbpath: 數(shù)據(jù)文件路徑,注:文件夾必須是存在诸蚕,mongod不會自動創(chuàng)建
  • logpath: 日志文件名稱步势,這個不需要提前新建,若不存在mongod會自動創(chuàng)建
  1. 連接任意一個實例挫望,這里就選擇27017這個默認端口
mongo
  1. 啟動副本集
rs.initiate({
    _id: "rs0",
    members: [
        { _id: 0, host: "127.0.0.1:27017" },
        { _id: 1, host: "127.0.0.1:27018" }
    ]
})

參數(shù)說明

  • _id : 副本集名稱,就是啟動實例時指定那個名稱
  • members : 這個就是所有成員狂窑,_id每個成員的標(biāo)識媳板,整數(shù)型[0,255]

返回字段"ok" : 1 代表創(chuàng)建成功

rs.initiate({}),這里除了幾個必須的泉哈,都是使用默認配置去啟動蛉幸,更多配置參數(shù)可以參考replica-configuration

  1. 查看當(dāng)前配置信息
rs.conf()

返回參數(shù)說明

  1. 查看副本集信息
rs.status()

到這破讨,副本集就搭建完成

事務(wù)


  1. 連接副本集
mongo mongodb://127.0.0.1:27017,127.0.0.1:27018/?replicaSet=rs0
  1. 準備2條數(shù)據(jù)
db.balance.insert({ name: "Wilson", balance: 100 }, { writeConcern: { w: "majority", wtimeout: 2000 } });
db.record.insert({ name: "Wilson", change: 100, balance: 100, }, { writeConcern: { w: "majority", wtimeout: 2000 } });
測試正常提交

模擬一個扣錢動作,其中扣款和流水在一個事務(wù)里

session = db.getMongo().startSession({ readPreference: { mode: "primary" } });
balanceCol = session.getDatabase("mongo").balance;
recordCol = session.getDatabase("mongo").record;
session.startTransaction({ readConcern: { level: "local" }, writeConcern: { w: "majority" } });

try {
    balanceCol.updateOne({ "name": "Wilson" }, { $set: { "balance": 50 } });
    recordCol.insertOne({ "name": "Wilson", change: -50, balance: 50 });
} catch (error) {
    session.abortTransaction();
} 
session.commitTransaction();
session.endSession();

查看余額情況

db.balance.aggregate([
    { $lookup: { from: "record", localField: "name", foreignField: "name", as: "changs" } },
    { $project: { "_id": 0, "changs._id": 0, "changs.name": 0 } },
]);

結(jié)果

{ "name" : "Wilson", "balance" : 50, "changs" : [ { "change" : 100, "balance" : 100 }, { "change" : -50, "balance" : 50 } ] }
測試失敗回滾

事務(wù)內(nèi)多增加一個插入不存在的集合操作奕纫,讓事務(wù)報錯

session.startTransaction({ readConcern: { level: "local" }, writeConcern: { w: "majority" } });
try {
    balanceCol.updateOne({ "name": "Wilson" }, { $set: { "balance": -50 } });
    recordCol.insertOne({ "name": "Wilson", change: -50, balance: 0 });
    session.getDatabase("mongo").user.insert({ "time": new Date() });    //多增加操作一個不存在的表
} catch (error) {
    session.abortTransaction();
    throw error;
}
session.commitTransaction();
session.endSession();

返回報錯信息

2020-04-15T21:37:05.576+0800 E  QUERY    [js] uncaught exception: Error: command failed: {
        "errorLabels" : [
                "TransientTransactionError"
        ],
        "operationTime" : Timestamp(1586957825, 1),
        "ok" : 0,
        "errmsg" : "Transaction 0 has been aborted.",
        "code" : 251,
        "codeName" : "NoSuchTransaction",
        "$clusterTime" : {
                "clusterTime" : Timestamp(1586957825, 1),
                "signature" : {
                        "hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
                        "keyId" : NumberLong(0)
                }
        }
} :
_getErrorWithCode@src/mongo/shell/utils.js:25:13
doassert@src/mongo/shell/assert.js:18:14
_assertCommandWorked@src/mongo/shell/assert.js:583:17
assert.commandWorked@src/mongo/shell/assert.js:673:16
commitTransaction@src/mongo/shell/session.js:971:17
@(shell):1:1

再查看當(dāng)前余額情況

db.balance.aggregate([
    { $lookup: { from: "record", localField: "name", foreignField: "name", as: "changs" } },
    { $project: { "_id": 0, "changs._id": 0, "changs.name": 0 } },
]);
{ "name" : "Wilson", "balance" : 50, "changs" : [ { "change" : 100, "balance" : 100 }, { "change" : -50, "balance" : 50 } ] }

可以看到提陶,余額和流水都沒變化。

參考文章


Replication — MongoDB Manual

Transactions — MongoDB Manual

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末匹层,一起剝皮案震驚了整個濱河市隙笆,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌升筏,老刑警劉巖撑柔,帶你破解...
    沈念sama閱讀 218,755評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異您访,居然都是意外死亡铅忿,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,305評論 3 395
  • 文/潘曉璐 我一進店門灵汪,熙熙樓的掌柜王于貴愁眉苦臉地迎上來檀训,“玉大人,你說我怎么就攤上這事享言【欤” “怎么了?”我有些...
    開封第一講書人閱讀 165,138評論 0 355
  • 文/不壞的土叔 我叫張陵担锤,是天一觀的道長蔚晨。 經(jīng)常有香客問我,道長肛循,這世上最難降的妖魔是什么铭腕? 我笑而不...
    開封第一講書人閱讀 58,791評論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮多糠,結(jié)果婚禮上累舷,老公的妹妹穿的比我還像新娘。我一直安慰自己夹孔,他們只是感情好被盈,可當(dāng)我...
    茶點故事閱讀 67,794評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著搭伤,像睡著了一般只怎。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上怜俐,一...
    開封第一講書人閱讀 51,631評論 1 305
  • 那天身堡,我揣著相機與錄音,去河邊找鬼拍鲤。 笑死贴谎,一個胖子當(dāng)著我的面吹牛汞扎,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播擅这,決...
    沈念sama閱讀 40,362評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼澈魄,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了仲翎?” 一聲冷哼從身側(cè)響起痹扇,我...
    開封第一講書人閱讀 39,264評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎谭确,沒想到半個月后帘营,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,724評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡逐哈,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,900評論 3 336
  • 正文 我和宋清朗相戀三年芬迄,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片昂秃。...
    茶點故事閱讀 40,040評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡禀梳,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出肠骆,到底是詐尸還是另有隱情算途,我是刑警寧澤,帶...
    沈念sama閱讀 35,742評論 5 346
  • 正文 年R本政府宣布蚀腿,位于F島的核電站嘴瓤,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏莉钙。R本人自食惡果不足惜廓脆,卻給世界環(huán)境...
    茶點故事閱讀 41,364評論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望磁玉。 院中可真熱鬧停忿,春花似錦、人聲如沸蚊伞。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,944評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽时迫。三九已至颅停,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間掠拳,已是汗流浹背癞揉。 一陣腳步聲響...
    開封第一講書人閱讀 33,060評論 1 270
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人烧董。 一個月前我還...
    沈念sama閱讀 48,247評論 3 371
  • 正文 我出身青樓,卻偏偏與公主長得像胧奔,于是被迫代替她去往敵國和親逊移。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,979評論 2 355

推薦閱讀更多精彩內(nèi)容