请澄清我的疑问,我正在开发使用Firebase实时数据库的移动应用程序。网址是/ 要求/ 12345 / 已确认=“”
场景是:一次有2个手机应用程序(内部使用Firebase)读取Firebase节点数据(12345 /已确认)并检查该数据是否为null或为空,如果该数据为null或为空,则将使用其更新id(应用程序用户具有唯一的id)
问题是:同时,两者都读取数据为null并且都在更新值,如何避免这种情况?我们有什么机制可以锁定该节点吗?
这是使用的代码。
String node = "/" + "req" + "/" + requestId;
ValueEventListener postListener = new ValueEventListener() {
@Override
public void onDataChange(@NonNull DataSnapshot dataSnapshot) {
String driverIdd = preference.getLongDetail(Constants.DRIVER_ID);
Log.e("Test","Log::Going to Confirm Driver:::"+driverIdd);
String confirmed_walker = dataSnapshot.child("confirmed_walker").getValue(String.class);
Log.e("Test","Log::Confiremed::"+confirmed_walker);
if(confirmed_walker.isEmpty()){
Map<String, Object> updates = new HashMap<>();
updates.put(node + "/confirmed_walker",driverIdd);
databaseReference.updateChildren(updates).addOnCompleteListener(task -> {
Log.e("Test","Log::Confirmed Driver:::"+driverIdd);
}).addOnFailureListener(e -> {
});
}
}
@Override
public void onCancelled(@NonNull DatabaseError databaseError) {
}
};
databaseReference.child(
node).
addListenerForSingleValueEvent(postListener);
答案 0 :(得分:1)
您正在这里寻找Firebase数据库事务。来自documentation:
在处理可能被并发修改破坏的数据(例如增量计数器)时,可以使用事务操作。
一开始,Firebase事务可能有点不寻常,因为您没有明确地对数据进行锁定。取而代之的是,您编写一个函数以猜测方式调用数据库节点的当前值,并且该函数返回在这种情况下服务器应存储的新值。
在您的情况下,它看起来像这样:
databaseReference.child(node).runTransaction(new Transaction.Handler() {
@Override
public Transaction.Result doTransaction(MutableData data) {
if (data.getValue() == null) {
// TODO: call data.setValue(...) to set the initial data for the node
return Transaction.success(mutableData);
}
if (TextUtils.isEmpty(data.child("confirmed_walker").getValue(String.class))) {
// TODO: call data.setValue(...) to set the data for a confirmed walker
// Report transaction success, so that the server tries to commit it
return Transaction.success(mutableData);
}
// Abort the transaction, since we have nothing to do
return Transaction.abort();
}
@Override
public void onComplete(DatabaseError databaseError, boolean b,
DataSnapshot dataSnapshot) {
// Transaction completed
Log.d(TAG, "runTransaction:onComplete:" + databaseError);
}
});
*更新**:由于您似乎只在读/写confirmed_walker
节点,因此可以仅在该节点上运行事务,既减少了争用,又使代码更简单:
databaseReference.child(node).child("confirmed_walker").runTransaction(new Transaction.Handler() {
@Override
public Transaction.Result doTransaction(MutableData data) {
if (data.getValue() == null) {
// Set the driver ID for this node
String driverIdd = preference.getLongDetail(Constants.DRIVER_ID);
data.setValue(driverIdd);
// Report transaction success, so that the server tries to commit it
return Transaction.success(mutableData);
}
// Abort the transaction, since we have nothing to do
return Transaction.abort();
}
@Override
public void onComplete(DatabaseError databaseError, boolean b,
DataSnapshot dataSnapshot) {
// Transaction completed
Log.d(TAG, "runTransaction:onComplete:" + databaseError);
}
});