我有一个运行在docker容器上的mongo实例:
docker run
-d
--name mongo
-e MONGO_INITDB_ROOT_USERNAME=bla
-e MONGO_INITDB_ROOT_PASSWORD=bla
-p 27017:27017
mongo
和我有一个进程使用mongo如下方式:
def init():
client = pymongo.MongoClient('mongodb://bla:bla@localhost:27017')
db = client['db']
collection = db['col']
collection.insert_one({'ok': False})
return collection
def critical_section(collection):
if list(collection.find({'ok': False})):
# do stuff
collection.update_one({'ok': False}, {'ok': True})
collection = init()
critical_section(collection)
我有许多并发进程运行critical_section
函数,所以我想在临界区之前锁定集合,然后解锁它(如果我不这样做,2个进程可以find
一个文档,但是,第一个将设法更新,第二个将失败…)
我用这个答案来锁定db:
collection = init()
pymongo.MongoClient('mongodb://bla:bla@localhost:27017')['admin'].command('fsync', lock=True)
critical_section(collection)
pymongo.MongoClient('mongodb://bla:bla@localhost:27017')['admin'].command('fsyncUnlock')
然而,这只锁定了写操作,这对我来说并没有削减它。
- 如何锁定读取?
- 我可以锁定集合,而不是整个数据库?
- 我现在认为我可以跳过查找,并做一个
if collection.update_one().updated_count == 1: # do stuff...
,虽然我不确定它是否完全解决了我需要的,因为没有find
,我无法知道我更新的项目的id
参见MongoDB并发更新同一文档不表现原子的示例实现。
我可以锁定集合,而不是整个数据库吗?
试图用锁来解决并发问题(即使数据库不能被多个客户端使用)是次优的,因为它不能扩展,因此对于实际上具有并发性的情况是没有用的。
这就是为什么条件更新、MVCC/快照读取关注和类似的结构提供原子性和一致性,但不提供锁定的原因。