考虑以下几点:火力地堡交易错误
function useCredits(userId, amount){
var userRef = firebase.database().ref().child('users').child(userId);
userRef.transaction(function(user) {
if (!user){
return user;
}
user.credits -= amount;
return user;
}, NOOP, false);
}
function notifyUser(userId, message){
var notificationId = Math.random();
var userNotificationRef = firebase.database().ref().child('users').child(userId).child('notifications').child(notificationId);
userNotificationRef.transaction(function(notification) {
return message;
}, NOOP, false);
}
这些都是从同一个节点JS过程调用。
用户看起来是这样的:
{
"name": 'Alex',
"age": 22,
"credits": 100,
"notifications": {
"1": "notification 1",
"2": "notification 2"
}
}
当我跑我的压力测试中,我注意到,有时传递给userRef交易更新功能的用户对象是不是只有以下完整的用户:
{
"notifications": {
"1": "notification 1",
"2": "notification 2"
}
}
这显然会导致错误,因为user.credits不存在。
可疑传递给userRef事务的update函数的用户对象与userNotificationRef事务的更新函数返回的数据相同。
为什么会出现这种情况?如果我在用户父位置上运行这两个事务,这个问题就会消失,但这是一个不太理想的解决方案,因为我然后有效地锁定并读取了整个用户对象,这在添加一次写入通知时是多余的。
我不知道交易有这样的问题...... +1。你如何建议重新设计这个“增值”操作而不需要交易? – qxz
非常感谢您的详细回复 - 理解。看起来交易有些失败 - 在我看来,客户不应该担心所有这些考虑因素。您如何建议在不使用Firebase交易的情况下对银行账户余额进行建模?如果没有一个强大的方法来处理这个使用交易,那么我觉得这是一个严重的限制。另一个问题是能够在事务上更新某个值,并同时自动更新其他位置。 – user3391835
这是所有来之不易的经历,重点在*难*。只要你牢记上述注意事项,事务对于简单的增量可能就不错了。另一种方法是将“+ N”条目推送到日志中,并让服务器定期使用事务处理它们,这应该更加健壮并且最终保持一致。客户端可以读取最后的聚合值并记录,以便即时计算当前值。深度原子更新是可能的,但不能是事务性的 - 再次,基于日志的设计是您的朋友。 – Piotr