Mongodb 開發之路 22 事務開發:多文檔事務

一,開始之前
1. Mongodb 雖然已經在4.2 開始全面支持多文檔事務,但不代表大家應該毫無節制地使用它。
相反,對事務的使用原則應該是:能不用盡量不用。
2. 通過合理地設計文檔模型,可以規避大部分使用事務的必要性
     爲什麼? 事務= 鎖,節點協調,額外開銷,性能影響


二,MongoDB ACID 多文檔事務支持

事務屬性 支持程度
Atomocity 原子性 單表單文檔: 1.x 就支持
複製集多表多行: 4.0 複製集
Consistency 一致性 writeConcern,readConcern(3.2)
isolation 隔離性 readConcern(3.2)
Durablity 持久性  journal and Replication

三,使用方法
    MongoDB 多文檔會務的使用方式與關係數據庫非常相似:
 try  (ClientSession clientSession = client.startSession()) {
       clientSession.startTransaction();
       collection.insertOne(clientSession, docOne);
       collection.insertOne(clientSession, docTwo);
       clientSession.commitTransaction();
       )

四, 事務的隔離級別
    1. 事務完成前,事務外的操作對該事務所做的修改不可訪問
    2. 如果事務內使用{readConcern: "snapshot"}, 則可以達到可重複讀 Repeatable Read


 五, 實驗:  啓用事務後的隔離性
 
 ``````
 db.tx.insertMany([{x:1},{x:2}]);
 var session = db.getMongo().startSession();
 session.startTransaction();
 var coll= session.getDatabase('test').getCollection('tx');
 coll.updateOne({x:1},{$set:{y:1}});             事務內操作
 coll.findOne({x:1});                                   事務內操作
 db.tx.findOne({x:1});                      事務外操作
 session.abortTransaction();
``````
六, 實驗: 可重複讀 Repeatable Read

``````
var session= db.getMongo().startSession();
session.startTransaction({
              readConcern: {level: "snapshot"},
          writeConcern:{w:"majority"}});
var coll = session.getDatabase('test').getCollection('tx')
coll.findOne({x:1});  返回:{x:1}
db.tx.updateOne({x:1},{$set:(y:1)});
db.tx.findOne({x:1});
coll.findOne({x:1});
session.abortYransaction();

七, 事務寫機制
MongoDB 的事務錯誤處理機制不同於關係數據庫
    1. 當一個事務開始後,如果事務要修改的文檔在事務外部被修改過,則事務修改這個文檔時會觸發Abort 錯誤,因爲此時
    的修改衝突了
    2. 這種情況下,只需要簡單地重做事務就可以了
    3. 如果一個事務已經開始修改一個文檔,在事務以外嘗試修改同一個文檔,則事務以外的修改會等待事務完成才能繼續錦繡

 八, 實驗:寫衝突
 繼續使用上個實驗的tx 集合
 開兩個 mongo shell 均執行下面語句
     var session = db.getMongo().startSession();
     session.startTransaction({readConcern: {level: "snapshot"},writeConcern:{w:"majority"}});
     var coll= session.getDatabase('test').getCollection("tx");
   
   窗口1:
   coll.updateOne({x:1},{$set:{y:1}});
   // 正常結束
   窗口2:
   coll.updateOne({x:1},{$set:{y:2}})
   //異常-解決方案:重啓事務

   九,注意事項
       1. 可以實現和關係型數據庫類似的事務場景
       2. 必須使用與MongoDB 4.2 兼容的驅動
       3. 事務默認必須在60秒(可調) 內完成,否則將被取消
       4. 涉及事務的分片不能使用仲裁節點
       5. 事務會影響chunk 遷移效率。正在遷移的chunk 也可能造成事務提交失敗(重試即可);
       6. 多文檔事務中的讀操作必須使用主節點讀
       7. readConcern 只應該在事務級別設置,不能設置在每次讀寫操作上

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章