mongodb 4.0已經(jīng)支持副本集級(jí)別的事務(wù)了,而且現(xiàn)在是穩(wěn)定版.下一個(gè)版本4.2準(zhǔn)備支持分片的事物.我因?yàn)閿?shù)據(jù)庫規(guī)模較小,暫時(shí)用不到分片的規(guī)模,于是就先升級(jí)到4.0版本.
提醒: mongo官方建議你不要把事務(wù)當(dāng)救命稻草, 更多的時(shí)候要依賴良好的設(shè)計(jì)模式來減少使用多文檔事務(wù)的機(jī)會(huì),畢竟事務(wù)是會(huì)影響性能的.
首先貼出官方文檔,鳥語好的同學(xué)可以直接啃生肉.
升級(jí)獨(dú)立版本到mongodb 4.0
升級(jí)副本集到mongodb 4.0
升級(jí)分片到mongodb 4.0
先備份數(shù)據(jù)庫,雖說升級(jí)后數(shù)據(jù)庫會(huì)保留下來,但為了不要最后演變成刪庫鬧劇.還是老老實(shí)實(shí)的備份數(shù)據(jù)庫吧
mongodump --host 127.0.0.1:27017 --gzip --db db_name --username your_account --password 'your_password' --authenticationDatabase db_name -o your_bak_path
升級(jí)前檢查/要求:
版本檢查
db.adminCommand( { getParameter: 1, featureCompatibilityVersion: 1 } )
設(shè)置版本兼容性信息
db.adminCommand( { setFeatureCompatibilityVersion: "3.6" } )
- mongodb3.6要求,如果你不滿足這個(gè)條件(比如你是3.4版本),那么請(qǐng)先升級(jí)到3.6的版本.
- 兼容性檢查,取消了一些特性,如果你當(dāng)前的系統(tǒng)用到了這些特性,恐怕你要一些額外的工作,具體的兼容性檢查信息在這里
由于我用的是ubuntu16.04我就用這個(gè)系統(tǒng)來演示.
- 添加mongodb的key
sudo apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv 9DA31620334BD75D9DCB49F368818C72E52529D4
- 創(chuàng)建源列表
echo "deb [ arch=amd64,arm64 ] https://repo.mongodb.org/apt/ubuntu xenial/mongodb-org/4.0 multiverse" | sudo tee /etc/apt/sources.list.d/mongodb-org-4.0.list
- 更新apt源
sudo apt-get update
- 安裝mongodb 4.0
注意,安裝之前必須先停止mongodb的服務(wù),否則會(huì)提示安裝成功但仍然是原來的3.6版本
sudo apt-get install -y mongodb-org
也可以這么安裝
sudo apt-get install -y mongodb-org=4.0.0 mongodb-org-server=4.0.0 mongodb-org-shell=4.0.0 mongodb-org-mongos=4.0.0 mongodb-org-tools=4.0.0
接下來,讓我們測(cè)試一下.
事務(wù)的限制條件
- 數(shù)據(jù)庫必須工作在副本集或者分片模式.單機(jī)模式是不支持事務(wù)的. 這點(diǎn)不是問題,把單機(jī)轉(zhuǎn)換為只有一個(gè)成員的副本集就好了.另外,如果你的兼容性檢查顯示的是3.6版本的話也不行.
*兼容性檢查命令 *
db.adminCommand( { getParameter: 1, featureCompatibilityVersion: 1 } )
事務(wù)不向下兼容,必須把兼容性提高到4.0
提升版本兼容性
db.adminCommand( { setFeatureCompatibilityVersion: "4.0" } )
- 多文檔事務(wù)執(zhí)行的時(shí)候,不會(huì)自動(dòng)創(chuàng)建命名空間. 也就是說,如果你的collection還未建立的話, 你執(zhí)行事務(wù)的時(shí)候會(huì)報(bào)錯(cuò).
pymongo.errors.OperationFailure: Cannot create namespace mq_db.t1 in multi-document transaction.
這個(gè)問題是我估計(jì)是由于事務(wù)的實(shí)現(xiàn)方式導(dǎo)致的.至于能不能打開自動(dòng)建表的功能我沒找到.這個(gè)使用的時(shí)候要留心這一點(diǎn).
-
驅(qū)動(dòng)和數(shù)據(jù)庫版本要求
如果你出現(xiàn)下面的這樣的錯(cuò)誤
AttributeError: 'ClientSession' object has no attribute 'start_transaction'
那么很可能是你的數(shù)據(jù)庫或者驅(qū)動(dòng)不滿足要求.請(qǐng)保證:
- mongodb 數(shù)據(jù)庫至少4.0
- pymongo 至少3.7版本
演示代碼 python3
import pymongo
user = "your_account" # 數(shù)據(jù)庫用戶名
password = "your_password" # 數(shù)據(jù)庫密碼
db_name = "your_db" # 庫名稱
mechanism = "SCRAM-SHA-1" # 加密方式,注意,不同版本的數(shù)據(jù)庫加密方式不同。
"""mongodb配置信息"""
mongodb_setting = {
"host": "server_ip:27017", # 數(shù)據(jù)庫服務(wù)器地址
"localThresholdMS": 30, # 本地超時(shí)的閾值,默認(rèn)是15ms,服務(wù)器超過此時(shí)間沒有返回響應(yīng)將會(huì)被排除在可用服務(wù)器范圍之外
"maxPoolSize": 100, # 最大連接池,默認(rèn)100,不能設(shè)置為0,連接池用盡后,新的請(qǐng)求將被阻塞處于等待狀態(tài).
"minPoolSize": 0, # 最小連接池,默認(rèn)是0.
"waitQueueTimeoutMS": 30000, # 連接池用盡后,等待空閑數(shù)據(jù)庫連接的超時(shí)時(shí)間,單位毫秒. 不能太小.
"authSource": db_name, # 驗(yàn)證數(shù)據(jù)庫
'authMechanism': mechanism, # 加密
"readPreference": "primaryPreferred", # 讀偏好,優(yōu)先從盤,如果是從盤優(yōu)先, 那就是讀寫分離模式
"username": user, # 用戶名
"password": password # 密碼
}
class DB:
"""自定義單例模式客戶端連接池"""
def __new__(cls):
if not hasattr(cls, "instance"):
conns = pymongo.MongoClient(**mongodb_setting)
cls.instance = conns
return cls.instance
def get_client() -> pymongo.MongoClient:
"""
獲取一個(gè)MongoClient(一般用于生成客戶端session執(zhí)行事物操作)
:return:
"""
mongo_client = DB()
return mongo_client
"""開始測(cè)試事務(wù),注意: t1和t2請(qǐng)?zhí)崆皠?chuàng)建,事務(wù)不會(huì)自己創(chuàng)建collection"""
client = get_client()
t1 = client[db_name]['t1'] # 操作t1表的collection,db_name是你的數(shù)據(jù)庫名,你可以這么寫client.db_name.collection_name
t2 = client[db_name]['t2'] # # 操作t2表的collection
with client.start_session(causal_consistency=True) as session:
"""事物必須在session下執(zhí)行,with保證了session的正常關(guān)閉"""
with session.start_transaction():
"""一旦出現(xiàn)異常會(huì)自動(dòng)調(diào)用session.abort_transaction()"""
t1.insert_one(document={"name": "jack"}, session=session) # 注意多了session這個(gè)參數(shù)
k = dict()['name'] # 制造一個(gè)錯(cuò)誤,你會(huì)發(fā)現(xiàn)t1和t2的插入都不會(huì)成功.
t2.insert_one(document={"name": "jack2"}, session=session)
事務(wù)必須運(yùn)行在一個(gè)clientSession的session周期內(nèi).嵌套了2個(gè)with.這只是個(gè)示范,生產(chǎn)環(huán)境請(qǐng)自行封裝.
順便說一下,mongodb現(xiàn)在已經(jīng)支持分片的多文檔事物了.