如果您愿意在更新“连接表”时锁定所有三个集合的所有更新,则可以使用应用程序级锁定来实现这一点。
简短版本:您创建一个“锁”集合。在更新三个集合 cA、cB 或 cC 中的任何一个之前,每个客户端都必须获得一个“写锁”。它通过更新 'locks' 集合中的文档来实现。当您准备好执行批量更新时,您将获取“写锁”,执行更新并释放锁。
这是一些实现锁定的简单示例代码。请注意,此代码有几个限制:
- 没有死锁检测或预防
- 没有锁超时
- 尝试重新锁定锁定的资源总是会失败,即使之前已成功获取锁定
解决这些限制留给读者作为练习。
XDB = db.mylocks;
/*
* Set up the locking collection
*/
function setup_locking( res_name ) {
var doc = { _id: res_name, state: "UNLOCKED", locker: null };
// upsert to create document if it does not exist
XDB.update( {id: res_name}, doc, true );
}
/*
* Lock the resource named 'res_name' by process named 'proc'
*
* Returns 'true' if resource was acquired, 'false' if it was not acquired
*/
function lockit( res_name, proc ) {
/*
* 1) Change state to LOCKED if & only if it was previously UNLOCKED
*/
ret = XDB.findAndModify( {
query: { _id:res_name, state:"UNLOCKED" } ,
update: {"$set": { state:"LOCKED", locker: proc } },
fields: { state:1, locker:1 },
new: true
}
);
/*
* Return 'true' if this process acquired this resource
*/
if ( ret && (ret.state == "LOCKED") && (ret.locker == proc) )return true;
/*
* 2) Failed to acquire this resource
*/
return false;
}
/*
* Unlock the resource named 'res_name' previously held by 'proc'
*/
function unlockit( res_name, proc ) {
// Unlock resource if this process had previously acquired it
XDB.findAndModify( {
query: { _id:res_name, locker: proc, state:"LOCKED" } ,
update: {"$set": { state:"UNLOCKED", locker: null } },
}
);
}
/*
* Check to see if resource 'res_name' is currently held by 'proc'
*/
function has_lock( res_name, proc ) {
res = XDB.findOne({_id: res_name, locker:proc} );
if (res == null) return false;
return true;
}
XDB.drop();
setup_locking('collectionA');
result = lockit( 'collectionA', 'app1');
print("1: result =", result);
result = lockit( 'collectionA', 'app2');
print("2: result =", result);
result = lockit( 'collectionA', 'app1');
print("3a: result =", result);
result = has_lock( 'collectionA', 'app1');
print("3b: result =", result);
result = has_lock( 'collectionA', 'app2');
print("3c: result =", result);
unlockit( 'collectionA', 'app1');
result = lockit( 'collectionA', 'app2');
print("4: result =", result);