Я работаю над собственным Android-приложением на базе Java и Firebase
, для которого требуются множественные записи (с использованием SingleValueEventListener
или транзакции) в различные ссылки на БД в реальном времени на основе определенных действий.
Это что-то вроде:
- Пользователь нажимает кнопку.
- В SingleValueEventListener1 / Transaction1 для DB ref 1 ссылка на DB 1 обновляется.
- Как только DB ref 1 успешно обновляется, в другом SingleValueEventListener2 / Transaction2, вложенном в SingleValueEventListener1 / Transaction1, ссылка на DB 2 начинает обновляться.
... и т. д.
Что мне нужно?
Обновление второго расположения БД, только после того, как первое местоположение, которое я пытаюсь обновить, прошло успешно. Местоположения облегчают одновременные обновления.
Предварительное исследование:
Я просмотрел различные посты и вопросы о переполнении стека, касающиеся отката БД, одновременных обновлений, обновлений в нескольких местах, правил баз данных и безопасности, но ни один из них не помог мне.
На какие ресурсы я смотрел?
Отмена обновления Firebase , Откат фиксации Firebase , Мультизапись Firebase , Обновления Firebase для нескольких локаций
В чем проблема?
Нет проблем с обновлением ссылок. проблема заключается в том, что если ссылка на БД 1 обновляется успешно, а обновление ссылки на БД 2 не удается, то у меня нет возможности откатить ссылку 1 до предыдущего состояния.
Требуется ли такой подход?
В моем случае, к сожалению, да.
Какие есть варианты решения этой проблемы?
Я могу сохранить предыдущее состояние ссылки 1 и, если обновление не удастся для ссылки 2, я могу переписать предыдущее состояние ссылки 1.
Но эти местоположения поддерживают одновременные обновления, и к тому времени, когда я возвращаюсь к предыдущему состоянию, предыдущее состояние тоже может быть обновлено. Предыдущие данные могут устареть, и переопределение ссылки этими данными может привести к потере данных. Решение всех этих проблем требует нежелательных сложностей в коде, которые могут вообще не гарантировать решение проблемы.
Транзакции, безусловно, будут пытаться обновить Ref 2 до успешного завершения, но до определенного времени, и, возможно, сбой записи во втором месте вызван потерей сетевого подключения, что объясняет часть моего беспокойство.
Другой вариант - изменить структуру БД и переместить все ссылки на несколько БД в одно отдельное местоположение, чтобы в случае сбоя обновления местоположения ничего не изменилось в соответствии с 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);
Это нетривиальная, но сложная для меня проблема, которую нужно решить, так как большая часть приложения выполняется иначе. Я готов переделать на основе ваших предложений. Пожалуйста, не стесняйтесь предлагать, любая помощь более чем ценится со смирением и благодарностью.