您好,登錄后才能下訂單哦!
今天就跟大家聊聊有關(guān)mongodb有沒(méi)有事務(wù),可能很多人都不太了解,為了讓大家更加了解,小編給大家總結(jié)了以下內(nèi)容,希望大家根據(jù)這篇文章可以有所收獲。
MongoDB 4.0 引入的事務(wù)功能,支持多文檔 ACID 特性,例如使用 mongo shell 進(jìn)行事務(wù)操作。
> s = db.getMongo().startSession() session { "id" : UUID("3bf55e90-5e88-44aa-a59e-a30f777f1d89") } > s.startTransaction() > session.getDatabase("mytest").coll01.insert({x: 1, y: 1}) WriteResult({ "nInserted" : 1 }) > session.getDatabase("mytest").coll02.insert({x: 1, y: 1}) WriteResult({ "nInserted" : 1 }) > s.commitTransaction() (或者 s.abortTransaction()回滾事務(wù))
支持 MongoDB 4.0 的其他語(yǔ)言 Driver 也封裝了事務(wù)相關(guān)接口,用戶(hù)需要?jiǎng)?chuàng)建一個(gè) Session,然后在 Session 上開(kāi)啟事務(wù),提交事務(wù)。例如:
python 版本
with client.start_session() as s: s.start_transaction() collection_one.insert_one(doc_one, session=s) collection_two.insert_one(doc_two, session=s) s.commit_transaction()
java 版本
try (ClientSession clientSession = client.startSession()) { clientSession.startTransaction(); collection.insertOne(clientSession, docOne); collection.insertOne(clientSession, docTwo); clientSession.commitTransaction(); }
一、預(yù)備工作
1、MongoDB需要4.0版本+
2、需要自己搭建MongoDB復(fù)制集,單個(gè)mongodb server 不支持事務(wù)。
事務(wù)原理:mongodb的復(fù)制至少需要兩個(gè)節(jié)點(diǎn)。其中一個(gè)是主節(jié)點(diǎn),負(fù)責(zé)處理客戶(hù)端請(qǐng)求,其余的都是從節(jié)點(diǎn),負(fù)責(zé)復(fù)制主節(jié)點(diǎn)上的數(shù)據(jù)。mongodb各個(gè)節(jié)點(diǎn)常見(jiàn)的搭配方式為:一主一從、一主多從。主節(jié)點(diǎn)記錄在其上的所有操作oplog,從節(jié)點(diǎn)定期輪詢(xún)主節(jié)點(diǎn)獲取這些操作,然后對(duì)自己的數(shù)據(jù)副本執(zhí)行這些操作,從而保證從節(jié)點(diǎn)的數(shù)據(jù)與主節(jié)點(diǎn)一致。
3、搭建復(fù)制集步驟
啟動(dòng)mongo主節(jié)點(diǎn)實(shí)例,bin目錄下命令窗口執(zhí)行,復(fù)制集命名為doudou, 8080端口的數(shù)據(jù)庫(kù)文件位于db1目錄下,--dbpath=路徑寫(xiě)自己的,啟動(dòng)后勿關(guān)閉命令窗口
mongod --replSet doudou --dbpath=E:\mongoDb\data\db1 --port=8080
啟動(dòng)mongo從節(jié)點(diǎn)實(shí)例,bin目錄下命令窗口執(zhí)行,復(fù)制集命名為doudou, 8081端口的數(shù)據(jù)庫(kù)文件位于db2目錄下,--dbpath=路徑寫(xiě)自己的,啟動(dòng)后勿關(guān)閉命令窗口
mongod --replSet doudou --dbpath=E:\mongoDb\data\db2 --port=8081
兩個(gè)節(jié)點(diǎn)啟動(dòng)后,bin目錄下打開(kāi)命令窗口,連接主節(jié)點(diǎn)
mongo --port=8080
命令初始化
rs.initiate()
兩個(gè)節(jié)點(diǎn)啟動(dòng)后,bin目錄下打開(kāi)命令窗口,連接主節(jié)點(diǎn)
mongo --port=8080
成功后如圖:
命令初始化
rs.initiate()
效果如圖:
成功的結(jié)果是(ok項(xiàng)是1,失敗是0)
查看是否是主節(jié)點(diǎn) rs.isMaster()
查看復(fù)制集狀態(tài) rs.status()
初始化配置
rs.conf()
向主節(jié)點(diǎn)添加從節(jié)點(diǎn)
rs.add("localhost:8081")
查看主節(jié)點(diǎn)狀態(tài)
rs.status()
復(fù)制集配置完成。
二、復(fù)制集中的坑點(diǎn)
1、需使用mongoose.connection對(duì)集合進(jìn)行事務(wù)操作,其他model的CRUD方法不支持事務(wù)。
mongoose.connection.collection('集合名') // 注:集合名需要小寫(xiě)且加s,如model為Cat,集合名這里應(yīng)寫(xiě)為cats
2、觸發(fā)Schema定義的中間件默認(rèn)值需要構(gòu)造model實(shí)例
const CatSchema = new Schema({ name: { type: String default: 'cat' }, created: { type: Date, default: Date.now } }) const Cat = mongoose.model('Cat', CatSchema) new Cat() // 觸發(fā)中間件
3、insertOne,findOneAndUpdate等方法對(duì)數(shù)據(jù)的新增,需上面第二點(diǎn)進(jìn)行依賴(lài),否則直接insertOne插入一條數(shù)據(jù),定義的默認(rèn)值不會(huì)觸發(fā),如created字段,chema內(nèi)部定義的type:Schema.ObjectId的相應(yīng)字段,insertOne插入后都會(huì)變成字符串類(lèi)型,不是Schema.ObjectId類(lèi)型。
// 解決方式 //新增 const Cat= new Cat(); const data = {name: 5} for (let key in data) { Cat[key] = data[key]; } db.collection('cats').insertOne(Cat); // 查詢(xún)修改 db.collection('cats') .findOneAndUpdate({_id: mongoose.Types.ObjectId(你的id)}, {$set: {name: 修改值}})
三、開(kāi)始事務(wù)
注:以下皆為egg實(shí)例代碼
封裝獲取session函數(shù)
// 獲取session,回滾事務(wù) async getSession(opt = { readConcern: { level: "snapshot" }, writeConcern: { w: "majority" } }) { const { mongoose } = this.app const session = await mongoose.startSession(opt); await session.startTransaction(); return session }
執(zhí)行事務(wù)邏輯
const { mongoose } = this.ctx.app; const session = await this.ctx.getSession(); const db = mongoose.connection; try { const data = this.ctx.request.body; const Cat = new this.ctx.model.Cat(); for (let key in data) { Cat[key] = data[key] } await db .collection('cats') .insertOne(Cat, { session }); // 提交事務(wù) await session.commitTransaction(); this.ctx.end(); } catch (err) { // 回滾事務(wù) await session.abortTransaction(); this.ctx.logger.error(new Error(err)); } finally { await session.endSession(); }
看完上述內(nèi)容,你們對(duì)mongodb有沒(méi)有事務(wù)有進(jìn)一步的了解嗎?如果還想了解更多知識(shí)或者相關(guān)內(nèi)容,請(qǐng)關(guān)注億速云行業(yè)資訊頻道,感謝大家的支持。
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀(guān)點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。