You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Firebase实时数据库中通过setValue实现ServerValue.increment的更新并获取结果?

Firebase Realtime Database:原子更新+获取值的实现困惑

我注意到runTransaction方法的完成监听器会返回一个快照currentData,这个应该就是事务执行完成后,该节点的最新数据快照:

@NonNull
public Result doTransaction(@NonNull MutableData currentData);

/**
 * 事务执行完成后会调用此方法
 *
 * @param error 无错误时为null,否则包含错误描述
 * @param committed 事务成功完成则为true,中止或出错则为false
 * @param currentData 该节点的当前数据,出错时为null
 */
public void onComplete(
    @Nullable DatabaseError error, boolean committed, @Nullable DataSnapshot currentData);

我推测用setValue(ServerValue.increment)的性能比runTransaction快一个数量级,但问题是,这种方式没有可靠的监听器能返回客户端刚执行更新后的最新值。

看setValue的方法定义:

/**
 * ...
 * @param value 要设置的值,null则删除现有数据
 * @param listener 操作完成后的回调监听器
 */
public void setValue(@Nullable Object value, @Nullable CompletionListener listener) {
  setValueInternal(value, PriorityUtilities.parsePriority(this.path, null), listener);
}

文档说监听器会返回“操作结果”,但看CompletionListener的定义就会发现,它只返回数据库引用,而不是更新后的快照:

/**
 * 用于监听操作是否被数据库服务器确认并完成的接口
 *
 * @since 1.1
 */
public interface CompletionListener {

  /**
   * 操作成功或失败时触发,失败时会返回错误信息,成功时error为null
   *
   * @param error 错误描述,成功时为null
   * @param ref 对应Firebase数据库节点的引用
   */
  public void onComplete(
      @Nullable final DatabaseError error, @NonNull final DatabaseReference ref);
}

也就是说,我如果要获取更新后的值,只能给这个引用加singleValueEventListener,但这种读取和之前的更新不是原子操作,高并发场景下会读到其他客户端修改后的值,完全不可靠。

我试了几种方法,但都不确定可行性:

Object db_config_ver = ServerValue.increment(1);

db_ver_ref.setValue(db_config_ver,
                    new DatabaseReference.CompletionListener() {
                        @Override
                        public void onComplete(@Nullable DatabaseError error, @NonNull DatabaseReference ref) {
                            if (error == null) {

                               // 加监听器?但高并发下非原子操作,必出问题!
                                ref.addListenerForSingleValueEvent(
                                        new ValueEventListener() {
                                            @Override
                                            public void onDataChange(@NonNull DataSnapshot snapshot) {

                                            }

                                            @Override
                                            public void onCancelled(@NonNull DatabaseError error) {

                                            }
                                        }
                                );

                                // 直接同步读取?同样非原子
                                long value = ref.get().getResult().getValue(Long.class);

                               // 读取ServerValue.increment对象本身?这只是个指令,不是实际值
                               System.out.println(db_config_ver);

                            }
                        }
                    }
            );

现在我有个疑问:是不是根本没有可靠的原子方式实现“更新+获取”?是不是只有runTransaction()能正确实现updateAndGet操作,而setValue和updateChildren虽然能配合ServerValue.increment完成更新,但无法原子性地获取更新后的结果?

内容的提问来源于stack exchange,提问作者Delark

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.07 07:50:18