java - 当单值事件或事务的嵌套 ValueEventListener 失败时,如何回滚到 Firebase Realtime DB for Android 中的先前状态?

标签 java android firebase firebase-realtime-database

我正在开发一个基于 Java 和 Firebase 的原生 Android 应用程序,该应用程序需要根据某些操作多次写入(使用 SingleValueEventListener 或事务)到不同的实时数据库引用。 它是这样的:

  1. 用户点击一个按钮。
  2. 在数据库引用 1 的 SingleValueEventListener1/Transaction1 中,更新了数据库引用 1。
  3. 一旦 DB 引用 1 成功更新,在嵌套在 SingleValueEventListener1/Transaction1 中的另一个 SingleValueEventListener2/Transaction2 中,DB 引用 2 开始更新。
    ...等等。

What do I need?

仅在我尝试更新的第一个位置成功后,才更新第二个数据库位置。这些位置有助于并发更新。

初步研究:

我查看了有关数据库回滚、并发更新、多位置更新、数据库规则和安全性的各种帖子和堆栈溢出问题,但没有一个对我的事业有所帮助。

我查看了哪些资源?

Firebase undoable update , Firebase commit rollback , Firebase multi-write , Firebase multi-location updates

问题是什么?

引用的更新没有问题。问题在于,如果 DB 引用 1 更新成功,而 DB 引用 2 更新失败,那么我无法将 Ref 1 回滚到之前的状态。

是否需要这种方法?

不幸的是,就我而言,是的。

有哪些解决方案?

  1. 我可以存储 Ref 1 的先前状态,如果 Ref 2 的更新失败,我可以重写 Ref 1 的先前状态。 但是这些位置支持并发更新,当我回滚到以前的状态时,以前的状态也可能已经更新。以前的数据可能会变得陈旧,并且用该数据覆盖 ref 可能会导致数据丢失。解决所有这些需要代码中不需要的复杂性的问题可能根本无法保证解决问题。

  2. Transactions 肯定会尝试更新 Ref 2 直到成功,但直到某个时间,并且可能是由于网络连接丢失导致无法在第二个位置写入,这部分解释了我的关注。

  3. 另一种选择是更改数据库设计并将所有多个数据库引用移动到一个位置,这样如果位置更新失败,则不会根据 Firebase 进行任何更改。但是,我设计数据库的方式似乎没问题。事实上,为了便于消除这个问题,如果我改变我的数据库结构,把东西转移到一个单一的位置,那对我来说是绝对错误的。用类似的情况来解释这一点,例如,在 StackOverflow 中,如果我对一个答案投赞成票,则回答者的声誉会发生变化,答案的状态会根据所涉及的人和票数发生变化, Activity 投票的人改变了,也可能是他的声誉。现在无法将上述所有 DB 引用合并为一个。

问题与 SingleValueEventListeners 或 Transactions 无关。

案例的简单代码示例,问题出在哪里?

为了简单起见,下面说明了一个 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. 使用交易
  2. 使用多位置更新

没有隐藏的第三种方式,所以如果你想以事务方式更新数据,你将不得不使用其中一种方式。

如果您写入的值不是基于当前值,您应该使用多位置更新,因为它具有更好的性能特征。有关更多信息,请阅读此博客文章:Client-side fan-out for data consistency .

如果您写入的值基于当前值,则需要使用事务。在这种情况下,确保您写入的数据在 JSON 中彼此靠近很重要,因为您实际上是在更新位置的顶部放置了一个(乐观的)锁。

关于java - 当单值事件或事务的嵌套 ValueEventListener 失败时,如何回滚到 Firebase Realtime DB for Android 中的先前状态?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50153919/

相关文章:

android - 有什么优化的方法可以在 android 中呈现大列表吗?

android - 在 imageview 中显示来自 Intent 的 jpg 图像

Android 4.4 - 播放默认音乐播放器

android - 如何编写 firebase 通知的单元测试?

java - JavaFX 和 FXML 项目之间的区别?

java - Hibernate 返回整数值

java - Android - Java ListView 项目顺序

java - 如何访问链表的元素?

firebase - Firebase Crashlytics 的 REST API?

ios - Firebase 使用苹果登录。新用户和回头客