Firebase允许更新资源transactionally。据我了解,客户端这样做就是向服务器发送请求“如果旧值是X,则使新值为Y”。如果存在争用,则服务器可以拒绝来自客户端的多个更新,直到接受一个更新。
现在,如果我想原子更新多个资源怎么办?
如果接受第一次更新会发生什么,然后在接受第二次更新之前断开客户端连接。有没有办法在原子事务中包含多个更新?如果没有,是否有这个问题的惯用解决方案?
答案 0 :(得分:44)
<强>更新强>
现在可以原子地更新多个位置。有关详细信息,请参阅this blog post。
var mergedUpdate = {};
mergedUpdate[ 'users/' + userId + '/widgets/' + widgetId ] = true;
mergedUpdate[ 'widgets/' + widgetId ] = widgetData;
var ref = new Firebase("https://<YOUR-FIREBASE-APP>.firebaseio.com/");
ref.update(mergedUpdate);
这不会强制执行事务数据(如果值当前为X,则将其设为Y),但此部分可以移动到security rules。例如,如果我们想要同时更新两个计数器,我们可以按如下方式添加规则:
{
"counter1": {
".validate": "newData.val() === (data.val()||0)+1"
},
"counter2"1 {
".validate": "newData.val() === (data.val()||0)+1"
}
}
现在我们可以尝试与上面相同的多路径更新。如果自上次从服务器读取值以来值已更改,则尝试将失败。我们可以检查if( error.code === 'PERMISSION_DENIED' ) { ... }
以查看失败是否是由验证引起的,并相应地重试。
原始帖子
执行此操作的唯一方法是在共同祖先上运行事务。
例如,如果要更新/ a / b / c和/ a / x / y,可以在/ a运行事务并更改这两个值。
这种方法的缺点是网络I / O可能会很昂贵,因为事务中的所有数据都需要下载然后发送回服务器。
您可能需要考虑的更复杂但可能更强大的方法是重构数据,以便存储编辑历史记录而不是存储实际值。例如,如果您要存储银行余额信息,则可以存储存款和取款历史记录。然后,当您想要获得余额时,您将回放整个历史记录并计算最终余额。
这种方法的优点在于它可以让你进行原子更新。例如,如果您将资金从accountA转移到accountB,您只需在日志末尾添加一个元素,说“从帐户A转帐到帐户B N美元”。附加单个元素是原子操作。
这是我们采用Firepad协作文本编辑器的方法。