如何在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
相关产品推荐
相关产品推荐

