讓你的mongodb支持事務(wù)---升級(jí)到mongodb 4.0

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" } )

  1. mongodb3.6要求,如果你不滿足這個(gè)條件(比如你是3.4版本),那么請(qǐng)先升級(jí)到3.6的版本.
  2. 兼容性檢查,取消了一些特性,如果你當(dāng)前的系統(tǒng)用到了這些特性,恐怕你要一些額外的工作,具體的兼容性檢查信息在這里

由于我用的是ubuntu16.04我就用這個(gè)系統(tǒng)來演示.

  1. 添加mongodb的key

sudo apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv 9DA31620334BD75D9DCB49F368818C72E52529D4

  1. 創(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

  1. 更新apt源

sudo apt-get update

  1. 安裝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ù)的限制條件

  1. 數(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" } )

  1. 多文檔事務(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).

  1. 驅(qū)動(dòng)和數(shù)據(jù)庫版本要求
    如果你出現(xiàn)下面的這樣的錯(cuò)誤

AttributeError: 'ClientSession' object has no attribute 'start_transaction'
那么很可能是你的數(shù)據(jù)庫或者驅(qū)動(dòng)不滿足要求.請(qǐng)保證:

  1. mongodb 數(shù)據(jù)庫至少4.0
  2. 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)支持分片的多文檔事物了.

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容