美文网首页mongodb
让你的mongodb支持事务---升级到mongodb 4.0

让你的mongodb支持事务---升级到mongodb 4.0

作者: justonlyyo | 来源:发表于2018-07-16 17:22 被阅读0次

    mongodb 4.0已经支持副本集级别的事务了,而且现在是稳定版.下一个版本4.2准备支持分片的事物.我因为数据库规模较小,暂时用不到分片的规模,于是就先升级到4.0版本.

    提醒: mongo官方建议你不要把事务当救命稻草, 更多的时候要依赖良好的设计模式来减少使用多文档事务的机会,毕竟事务是会影响性能的.

    首先贴出官方文档,鸟语好的同学可以直接啃生肉.
    升级独立版本到mongodb 4.0
    升级副本集到mongodb 4.0
    升级分片到mongodb 4.0

    先备份数据库,虽说升级后数据库会保留下来,但为了不要最后演变成删库闹剧.还是老老实实的备份数据库吧

    mongodump --host 127.0.0.1:27017 --gzip --db db_name --username your_account --password 'your_password' --authenticationDatabase db_name -o your_bak_path

    升级前检查/要求:
    版本检查

    db.adminCommand( { getParameter: 1, featureCompatibilityVersion: 1 } )

    设置版本兼容性信息

    db.adminCommand( { setFeatureCompatibilityVersion: "3.6" } )

    1. mongodb3.6要求,如果你不满足这个条件(比如你是3.4版本),那么请先升级到3.6的版本.
    2. 兼容性检查,取消了一些特性,如果你当前的系统用到了这些特性,恐怕你要一些额外的工作,具体的兼容性检查信息在这里

    由于我用的是ubuntu16.04我就用这个系统来演示.

    1. 添加mongodb的key

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

    1. 创建源列表

    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的服务,否则会提示安装成功但仍然是原来的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

    接下来,让我们测试一下.

    事务的限制条件

    1. 数据库必须工作在副本集或者分片模式.单机模式是不支持事务的. 这点不是问题,把单机转换为只有一个成员的副本集就好了.另外,如果你的兼容性检查显示的是3.6版本的话也不行.
      *兼容性检查命令 *

    db.adminCommand( { getParameter: 1, featureCompatibilityVersion: 1 } )

    事务不向下兼容,必须把兼容性提高到4.0

    提升版本兼容性

    db.adminCommand( { setFeatureCompatibilityVersion: "4.0" } )

    1. 多文档事务执行的时候,不会自动创建命名空间. 也就是说,如果你的collection还未建立的话, 你执行事务的时候会报错.

    pymongo.errors.OperationFailure: Cannot create namespace mq_db.t1 in multi-document transaction.
    这个问题是我估计是由于事务的实现方式导致的.至于能不能打开自动建表的功能我没找到.这个使用的时候要留心这一点.

    1. 驱动和数据库版本要求
      如果你出现下面的这样的错误

    AttributeError: 'ClientSession' object has no attribute 'start_transaction'
    那么很可能是你的数据库或者驱动不满足要求.请保证:

    1. mongodb 数据库至少4.0
    2. pymongo 至少3.7版本

    演示代码 python3

    import pymongo
    
    
    user = "your_account"              # 数据库用户名
    password = "your_password"       # 数据库密码
    db_name = "your_db"           # 库名称
    mechanism = "SCRAM-SHA-1"      # 加密方式,注意,不同版本的数据库加密方式不同。
    
    
    """mongodb配置信息"""
    mongodb_setting = {
        "host": "server_ip:27017",   # 数据库服务器地址 
        "localThresholdMS": 30,  # 本地超时的阈值,默认是15ms,服务器超过此时间没有返回响应将会被排除在可用服务器范围之外
        "maxPoolSize": 100,  # 最大连接池,默认100,不能设置为0,连接池用尽后,新的请求将被阻塞处于等待状态.
        "minPoolSize": 0,  # 最小连接池,默认是0.
        "waitQueueTimeoutMS": 30000,  # 连接池用尽后,等待空闲数据库连接的超时时间,单位毫秒. 不能太小.
        "authSource": db_name,  # 验证数据库
        'authMechanism': mechanism,  # 加密
        "readPreference": "primaryPreferred",  # 读偏好,优先从盘,如果是从盘优先, 那就是读写分离模式
        "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:
        """
        获取一个MongoClient(一般用于生成客户端session执行事物操作)
        :return:
        """
        mongo_client = DB()
        return mongo_client
    
    """开始测试事务,注意: t1和t2请提前创建,事务不会自己创建collection"""
    client = get_client()
    t1 = client[db_name]['t1']  # 操作t1表的collection,db_name是你的数据库名,你可以这么写client.db_name.collection_name
    t2 = client[db_name]['t2']  # # 操作t2表的collection
    with client.start_session(causal_consistency=True) as session:
        """事物必须在session下执行,with保证了session的正常关闭"""
        with session.start_transaction():
            """一旦出现异常会自动调用session.abort_transaction()"""
            t1.insert_one(document={"name": "jack"}, session=session)  # 注意多了session这个参数
            k = dict()['name']  # 制造一个错误,你会发现t1和t2的插入都不会成功.
            t2.insert_one(document={"name": "jack2"}, session=session)
    

    事务必须运行在一个clientSession的session周期内.嵌套了2个with.这只是个示范,生产环境请自行封装.

    顺便说一下,mongodb现在已经支持分片的多文档事物了.

    相关文章

      网友评论

        本文标题:让你的mongodb支持事务---升级到mongodb 4.0

        本文链接:https://www.haomeiwen.com/subject/euavpftx.html