Как выполнить откат к предыдущему состоянию в Firebase RealtimeDB для Android, когда не удается выполнить вложенный ValueEventListener для SingleValueEvent или Transaction? - PullRequest
0 голосов
/ 03 мая 2018

Я работаю над собственным Android-приложением на базе Java и Firebase, для которого требуются множественные записи (с использованием SingleValueEventListener или транзакции) в различные ссылки на БД в реальном времени на основе определенных действий. Это что-то вроде:

  1. Пользователь нажимает кнопку.
  2. В SingleValueEventListener1 / Transaction1 для DB ref 1 ссылка на DB 1 обновляется.
  3. Как только DB ref 1 успешно обновляется, в другом SingleValueEventListener2 / Transaction2, вложенном в SingleValueEventListener1 / Transaction1, ссылка на DB 2 начинает обновляться.
    ... и т. д.

Что мне нужно?

Обновление второго расположения БД, только после того, как первое местоположение, которое я пытаюсь обновить, прошло успешно. Местоположения облегчают одновременные обновления.

Предварительное исследование:

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

На какие ресурсы я смотрел?

Отмена обновления Firebase , Откат фиксации Firebase , Мультизапись Firebase , Обновления Firebase для нескольких локаций

В чем проблема?

Нет проблем с обновлением ссылок. проблема заключается в том, что если ссылка на БД 1 обновляется успешно, а обновление ссылки на БД 2 не удается, то у меня нет возможности откатить ссылку 1 до предыдущего состояния.

Требуется ли такой подход?

В моем случае, к сожалению, да.

Какие есть варианты решения этой проблемы?

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

  2. Транзакции, безусловно, будут пытаться обновить Ref 2 до успешного завершения, но до определенного времени, и, возможно, сбой записи во втором месте вызван потерей сетевого подключения, что объясняет часть моего беспокойство.

  3. Другой вариант - изменить структуру БД и переместить все ссылки на несколько БД в одно отдельное местоположение, чтобы в случае сбоя обновления местоположения ничего не изменилось в соответствии с Firebase. Тем не менее, способ, которым я разработал базу данных, кажется, хорошо. Фактически, чтобы облегчить устранение этой проблемы, если бы я изменил структуру своей базы данных и переместил вещи в одно-единственное место, это было бы абсолютно неправильно в моем случае. Чтобы объяснить это аналогичной ситуацией, например, в StackOverflow, если я добавлю ответ, репутация человека, который ответил, изменится, статус ответа изменится в отношении вовлеченных людей и количества голосов, активности человек, проголосовавший за изменения, может изменить свою репутацию. Теперь все вышеперечисленные ссылки на БД не могут быть объединены в одну.

Проблема не зависит от SingleValueEventListeners или транзакций.

Простой пример кода случая, для которого возникла проблема?

Этот пример иллюстрирует 2-уровневые вложенные EventListener с глубоким вложением (то же самое относится и к транзакциям), для простоты.

ValueEventListener outerListener = new ValueEventListener() {
  @Override
  public void onDataChange(DataSnapshot dataSnapshot) {
    if (dataSnapshot.exists()) {
    //do something
    //update DBRefOne
    DBRefOne.updateChildren(newOuterValue, new DatabaseReference.CompletionListener() {
      @Override
      public void onComplete(DatabaseError databaseError, DatabaseReference databaseReference) {
        ValueEventListener innerListener = new ValueEventListener() {
        @Override
        public void onDataChange(DataSnapshot dataSnapshot) {
          if (dataSnapshot.exists()) {
          //do something
          //update DBRefTwo
          DBRefTwo.updateChildren(newInnerValue);
          }
        }
        @Override
        public void onCancelled(DatabaseError databaseError) {
       // log error
      }
    };
    DBRefTwo.addListenerForSingleValueEvent(innerListener);
   }
 });
}
}
  @Override
  public void onCancelled(DatabaseError databaseError) {
  // log error
  }
};
DBRefOne.addListenerForSingleValueEvent(outerListener);

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

1 Ответ

0 голосов
/ 03 мая 2018

Существует два способа транзакционного обновления данных:

  1. Использовать транзакцию
  2. Использовать обновление нескольких местоположений

Третьего скрытого пути не существует, поэтому, если вы хотите обновить данные транзакциями, вам придется использовать один из них.

Если значения, которые вы вводите, не основаны на текущих значениях, вам следует использовать обновление нескольких местоположений, поскольку оно имеет гораздо лучшие характеристики производительности. Подробнее об этом читайте в этом блоге: Разветвление на стороне клиента для согласованности данных .

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

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