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" } )
- mongodb3.6要求,如果你不满足这个条件(比如你是3.4版本),那么请先升级到3.6的版本.
- 兼容性检查,取消了一些特性,如果你当前的系统用到了这些特性,恐怕你要一些额外的工作,具体的兼容性检查信息在这里
由于我用的是ubuntu16.04我就用这个系统来演示.
- 添加mongodb的key
sudo apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv 9DA31620334BD75D9DCB49F368818C72E52529D4
- 创建源列表
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的服务,否则会提示安装成功但仍然是原来的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
接下来,让我们测试一下.
事务的限制条件
- 数据库必须工作在副本集或者分片模式.单机模式是不支持事务的. 这点不是问题,把单机转换为只有一个成员的副本集就好了.另外,如果你的兼容性检查显示的是3.6版本的话也不行.
*兼容性检查命令 *
db.adminCommand( { getParameter: 1, featureCompatibilityVersion: 1 } )
事务不向下兼容,必须把兼容性提高到4.0
提升版本兼容性
db.adminCommand( { setFeatureCompatibilityVersion: "4.0" } )
- 多文档事务执行的时候,不会自动创建命名空间. 也就是说,如果你的collection还未建立的话, 你执行事务的时候会报错.
pymongo.errors.OperationFailure: Cannot create namespace mq_db.t1 in multi-document transaction.
这个问题是我估计是由于事务的实现方式导致的.至于能不能打开自动建表的功能我没找到.这个使用的时候要留心这一点.
-
驱动和数据库版本要求
如果你出现下面的这样的错误
AttributeError: 'ClientSession' object has no attribute 'start_transaction'
那么很可能是你的数据库或者驱动不满足要求.请保证:
- mongodb 数据库至少4.0
- 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现在已经支持分片的多文档事物了.
网友评论