Одновременное бронирование временного интервала в базе данных Firebase Real Time (проблема перезаписи) - PullRequest
0 голосов
/ 31 марта 2019

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

Моя техника бронирования заключается в вставке узла с ключом = метка времени и значением = идентификатор пользователя.

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

Я пытался использовать Сохранить данные как транзакции из документации Firebase Здесь . Но все равно резервы слотов перезаписывают друг друга.

Вот мой код:

                dbRef.child(String.valueOf(selectedDate.getTime())).runTransaction(new Transaction.Handler() {
            @Override
            public Transaction.Result doTransaction(MutableData mutableData) {
                BookingSlot s = mutableData.getValue(BookingSlot.class);
                if (s == null) {
                    //Upload new BookingSlot
                    dbRef.child(String.valueOf(selectedDate.getTime())).setValue(s);

                          );
                    }
                    return Transaction.success(mutableData);
                } else {
                    Toast.makeText(BookingActivity.this,"Slot has just been booked!",Toast.LENGTH_LONG).show();
                    //The chosen time has just been booked,

                }
                return Transaction.abort();
            }

            @Override
            public void onComplete(DatabaseError databaseError, boolean b,
                                   DataSnapshot dataSnapshot) {
                // Transaction completed
                Log.e("Booking", "postTransaction:onComplete:" + databaseError);
            }
        });

Я что-то здесь не так делаю?

1 Ответ

1 голос
/ 31 марта 2019

Ваш код, по-видимому, предполагает, что запуск транзакций дает вам блокировку местоположения, но это не так, как работают транзакции в Firebase.Вместо этого транзакции в Firebase работают с логикой сравнения и установки: клиент сообщает вам, каково (по его мнению) текущее значение, и вы сообщаете ему, что в этом случае становится новым значением, возвращая это новое значение.

Таким образом, вместо вызова .setValue(s) на месте, вы должны вернуть s в MutableData:

dbRef.child(String.valueOf(selectedDate.getTime())).runTransaction(new Transaction.Handler() {
    @Override
    public Transaction.Result doTransaction(MutableData mutableData) {
        BookingSlot s = mutableData.getValue(BookingSlot.class);
        if (s == null) {
            mutableData.setValue(uid); // TODO: pass in the UID of the user who's claiming this slot
            return Transaction.success(mutableData);
        } else {
            Toast.makeText(BookingActivity.this,"Slot has just been booked!",Toast.LENGTH_LONG).show();
            return Transaction.abort();
        }
    }

    @Override
    public void onComplete(DatabaseError databaseError, boolean b, DataSnapshot dataSnapshot) {
        Log.e("Booking", "postTransaction:onComplete:" + databaseError);
    }
});

С помощью приведенного выше кода клиенты не будут перезаписывать значение друг друга,

Но с Firebase вы всегда должны учитывать, что злоумышленник может написать свой собственный код для вашей базы данных, поскольку он может найти данные конфигурации в APK вашего приложения.Поэтому в правилах безопасности Firebase на стороне сервера вы также должны указывать, что на каждый слот можно претендовать только один раз.

Если заказы хранятся в /bookings, это можно сделать с помощью чего-то вроде:

{
  "rules": {
    "bookings": {
      "$timeslot": {
        ".write": "data.val() === null || data.val() === auth.uid"
      }
    }
  }
}

Это позволяет выполнять запись, если либо еще нет значения (слот не имеетбыло заявлено), или если пользователь пишет тот, кто требовал слот раньше (что позволило бы им очистить слот).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...