一、預備工作
1.MongoDB需要4.0版本+
2.需要自己搭建MongoDB復制集,單個mongodb server 不支持事務。
事務原理:mongodb的復制至少需要兩個節點。其中一個是主節點,負責處理客戶端請求,其余的都是從節點,負責復制主節點上的數據。mongodb各個節點常見的搭配方式為:一主一從、一主多從。主節點記錄在其上的所有操作oplog,從節點定期輪詢主節點獲取這些操作,然后對自己的數據副本執行這些操作,從而保證從節點的數據與主節點一致。
3.搭建復制集步驟
- 啟動mongo主節點實例,bin目錄下命令窗口執行,復制集命名為doudou, 8080端口的數據庫文件位於db1目錄下,--dbpath=路徑寫自己的,啟動后勿關閉命令窗口
mongod --replSet doudou --dbpath=E:\mongoDb\data\db1 --port=8080
- 啟動mongo從節點實例,bin目錄下命令窗口執行,復制集命名為doudou, 8081端口的數據庫文件位於db2目錄下,--dbpath=路徑寫自己的,啟動后勿關閉命令窗口
mongod --replSet doudou --dbpath=E:\mongoDb\data\db2 --port=8081
- 兩個節點啟動后,bin目錄下打開命令窗口,連接主節點
mongo --port=8080
- 命令初始化
rs.initiate()
- 兩個節點啟動后,bin目錄下打開命令窗口,連接主節點
mongo --port=8080
成功后如圖:

-
命令初始化
rs.initiate()
效果如圖:

成功的結果是(ok項是1,失敗是0)
查看是否是主節點 rs.isMaster()
查看復制集狀態 rs.status()
- 初始化配置
rs.conf()
- 向主節點添加從節點
rs.add("localhost:8081")
- 查看主節點狀態
rs.status()
復制集配置完成。
二、復制集中的坑點
1.需使用mongoose.connection對集合進行事務操作,其他model的CRUD方法不支持事務
mongoose.connection.collection('集合名') // 注:集合名需要小寫且加s,如model為Cat,集合名這里應寫為cats
2.觸發Schema定義的中間件默認值需要構造model實例
const CatSchema = new Schema({
name: {
type: String
default: 'cat'
},
created: {
type: Date,
default: Date.now
}
})
const Cat = mongoose.model('Cat', CatSchema)
new Cat() // 觸發中間件
3.insertOne,findOneAndUpdate等方法對數據的新增,需上面第二點進行依賴,否則直接insertOne 插入一條數據,定義的默認值不會觸發,如created字段,chema內部定義的type: Schema.ObjectId的相應字段,insertOne插入后都會變成字符串類型,不是Schema.ObjectId類型
// 解決方式
//新增
const Cat= new Cat();
const data = {name: 5}
for (let key in data) {
Cat[key] = data[key];
}
db.collection('cats').insertOne(Cat);
// 查詢修改
db.collection('cats')
.findOneAndUpdate({_id: mongoose.Types.ObjectId(你的id)}, {$set: {name: 修改值}})
三、開始事務
注:以下皆為egg實例代碼
- 封裝獲取session函數
// 獲取session,回滾事務 async getSession(opt = { readConcern: { level: "snapshot" }, writeConcern: { w: "majority" } }) { const { mongoose } = this.app const session = await mongoose.startSession(opt); await session.startTransaction(); return session } -
執行事務邏輯
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 }); // 提交事務 await session.commitTransaction(); this.ctx.end(); } catch (err) { // 回滾事務 await session.abortTransaction(); this.ctx.logger.error(new Error(err)); } finally { await session.endSession(); }
以上就是思考總結,完畢
