mongodb - GridFS put 命令在事务中使用时从 pymongo 挂起
问题描述
我正在使用 GridFS 在我的数据库中存储一些视频文件。我已经更新到 MongoDB 4.0 并尝试使用多集合事务模型。我面临的问题是put()
命令 gridfs 挂起系统。我使用它的方式如下:
client = pymongo.MongoClient(mongo_url)
db = client[db_name]
fs = gridfs.GridFS(db)
现在我尝试使用事务模型如下:
with db.client.start_session() as session:
try:
file_path = "video.mp4"
session.start_transaction()
with open(file_path, 'rb') as f:
fid = self.fs.put(f, metadata={'sequence_id': '0001'})
session.commit_transaction()
except Exception as e:
raise
finally:
session.end_session()
问题是put
命令挂起大约一分钟。然后它返回但提交失败。我有一种感觉,这是因为会话对象没有传递给put
命令,但我在帮助中看不到任何将会话作为输入的参数。挂起后,测试失败,堆栈如下:
回溯(最近一次通话最后):
session.commit_transaction()
File "/Users/xargon/anaconda/envs/deep/lib/python3.6/site-packages/pymongo/client_session.py", line 393, in commit_transaction
self._finish_transaction_with_retry("commitTransaction")
File "/Users/xargon/anaconda/envs/deep/lib/python3.6/site-packages/pymongo/client_session.py", line 457, in _finish_transaction_with_retry
return self._finish_transaction(command_name)
File "/Users/xargon/anaconda/envs/deep/lib/python3.6/site-packages/pymongo/client_session.py", line 452, in _finish_transaction
parse_write_concern_error=True)
File "/Users/xargon/anaconda/envs/deep/lib/python3.6/site-packages/pymongo/database.py", line 514, in _command
client=self.__client)
File "/Users/xargon/anaconda/envs/deep/lib/python3.6/site-packages/pymongo/pool.py", line 579, in command
unacknowledged=unacknowledged)
File "/Users/xargon/anaconda/envs/deep/lib/python3.6/site-packages/pymongo/network.py", line 150, in command
parse_write_concern_error=parse_write_concern_error)
File "/Users/xargon/anaconda/envs/deep/lib/python3.6/site-packages/pymongo/helpers.py", line 155, in _check_command_response
raise OperationFailure(msg % errmsg, code, response)
pymongo.errors.OperationFailure: Transaction 1 has been aborted.
编辑
我尝试将 put 块替换为:
try:
gf = self.fs.new_file(metadata={'sequence_id': '0000'})
gf.write(f)
finally:
gf.close()
但是,挂起再次发生在gf.close()
我还尝试GridIn
直接实例化,以便我可以提供会话对象,但失败为:
gin = gridfs.GridIn(root_collection=self.db["fs.files"], session=session)
gin.write(f)
gin.close()
这失败并显示错误消息:
It is illegal to provide a txnNumber for command createIndexes
解决方案
问题是 put 命令挂了大约一分钟
第一次尝试self.fs.put()
实际上并没有使用transactions,只是花了一段时间来上传文件。
然后在尝试提交(空)事务时上传完成后,不幸的是,由于上传所花费的时间,事务达到了最大生命周期限制。请参阅transactionLifetimeLimitSeconds。默认限制已设置为 60 秒以设置最大事务运行时间。
如果您正在考虑提高此限制,请记住,在创建事务快照后写入量进入 MongoDB,WiredTiger 缓存压力会增加。这种缓存压力只有在事务提交后才能释放。这就是 60 秒默认限制背后的原因。
为命令 createIndexes 提供 txnNumber 是非法的
首先,在多文档事务中不允许进行影响数据库目录的操作,例如创建或删除集合或索引。
PyMongo GridFS 的代码正在尝试为 GridFS 集合创建索引,当与事务会话一起使用时,服务器上禁止这样做(您可以使用会话但不能使用事务)。
我已经更新到 MongoDB 4.0 并尝试使用多集合事务模型
我建议对 GridFS 使用普通的数据库操作。MongoDB 多文档事务旨在用于多文档原子性。我认为在文件上传案例中没有必要。
推荐阅读
- azure - Azure AD B2C - 如何以编程方式创建消费者用户?
- python - 如何将 .txt 格式的文件导入 Python,具有规则的列结构(但不可靠的分隔符,如制表符、逗号等)
- javascript - AJAX .done() 在 JSON 响应中返回未定义的 $.each()
- java - Java 背景图像未在 Mac 上显示
- php - 使用 Laravel 和 ReactJS 前端处理 PayPal 智能结帐按钮
- node.js - Node.js 错误:找不到模块(本地文件)
- scala - val 是 Scala 中的一种变量吗?
- r - 使用 R 中的管道按变量聚合
- cookies - 您可以在没有设置名称的谷歌标签管理器中读取 Cookie 吗?
- python - AWS 预签名 URL 生成