【问题标题】:Firebase update node synchronizationFirebase 更新节点同步
【发布时间】:2019-07-06 21:02:44
【问题描述】:

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

【问题讨论】:

  • Id 只是字符串@Ashish
  • 我认为 Firebase 在 FIFS 上的工作意味着(先到先得)。所以我认为它以适当的方式管理 API 调用并更新第一个调用值,然后替换为第二个。
  • @Ashish 已编辑请检查
  • Firebase 中没有内置机制来锁定节点。但是,Firebase 确实具有可以处理尝试并发写入的情况的事务。

标签: android firebase firebase-realtime-database


【解决方案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);
    }
});

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-05-27
    • 2018-06-25
    • 1970-01-01
    • 2018-05-07
    • 1970-01-01
    相关资源
    最近更新 更多