一,開始之前
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 只應該在事務級別設置,不能設置在每次讀寫操作上