Firebase更新节点同步

时间:2019-07-06 09:57:00

标签: android firebase firebase-realtime-database

请澄清我的疑问,我正在开发使用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);

1 个答案:

答案 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);
    }
});