Синхронизация узла обновления Firebase - PullRequest
0 голосов
/ 06 июля 2019

Пожалуйста, проясните мои сомнения, я работаю над разработкой мобильного приложения, которое использует базу данных Firebase в реальном времени. URL является / REQ / 12345 / подтверждено = ""

Сценарий: когда 2 мобильных устройства одновременно (внутренне использующие Firebase) считывают данные узла Firebase (12345 / подтверждено) и проверяют, являются ли данные нулевыми или пустыми, если они нулевые или пустые, они обновляются с id (пользователь приложения имеет уникальный идентификатор)

Проблема в том, что одновременно оба читают данные как ноль и оба обновляют значение, как избежать такого сценария? Есть ли у нас какой-либо механизм для блокировки этого узла?

это код, использующий.

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 Ответ

1 голос
/ 06 июля 2019

Вы ищете транзакцию базы данных Firebase здесь. Из документации :

При работе с данными, которые могут быть повреждены одновременными изменениями, такими как инкрементные счетчики, вы можете использовать операцию транзакции.

Поначалу транзакция 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);
    }
});
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...