Java 非常简单的Firestore事务失败

Java 非常简单的Firestore事务失败,java,android,firebase,google-cloud-firestore,Java,Android,Firebase,Google Cloud Firestore,我正在为一个超级简单的交易而挣扎。它总是失败,消息为事务失败所有重试,但除了logcat上的错误消息外,没有其他错误消息 当我调试它时,我看到它被重试了好几次。我真的不知道为什么,因为其他事务运行时没有问题 我只想将一个文档从一个集合克隆到另一个集合。从视频到收藏夹我知道这可以在交易之外完成,正如@Alex指出的,但这只是失败的一部分,真正的交易更长 private void copy( final DocumentReference SOURCEDOCREF, final C

我正在为一个超级简单的交易而挣扎。它总是失败,消息为事务失败所有重试,但除了logcat上的错误消息外,没有其他错误消息

当我调试它时,我看到它被重试了好几次。我真的不知道为什么,因为其他事务运行时没有问题

我只想将一个文档从一个集合克隆到另一个集合。从视频到收藏夹我知道这可以在交易之外完成,正如@Alex指出的,但这只是失败的一部分,真正的交易更长

private void copy(
    final DocumentReference SOURCEDOCREF, 
    final CollectionReference TARGETCOLREF) {

        Transaction.Function<? extends Void> transaction = new Transaction.Function<Void>() {

            @Nullable
            @Override
            public Void apply(@NonNull Transaction transaction) throws FirebaseFirestoreException {

                DocumentSnapshot doc = transaction.get(SOURCEDOCREF);
                if (doc.exists()) {
                    DocumentReference favoriteRef = TARGETCOLREF.document("FV_" + doc.getId());
                    Map<String, Object> data = doc.getData();
                    transaction.set(favoriteRef, data);
                    return null;

                    // NOTE: This is reached, ie. the source doc exists
                    // the data recovered, and set into the transaction.
                } else
                    throw new FirebaseFirestoreException("Item does not exist", FirebaseFirestoreException.Code.NOT_FOUND);
            }
        };

        setMode(MODE_SPLASH);
        FirebaseFirestore.getInstance().runTransaction(transaction)
                .addOnSuccessListener(
                        (Activity) getContext(),
                        new OnSuccessListener<Object>() {
                            @Override
                            public void onSuccess(Object aVoid) {
                                setMode(MODE_FOLLOW);
                            }
                        })
                .addOnFailureListener(new OnFailureListener() {
                    @Override
                    public void onFailure(@NonNull Exception e) {
                        hide();
                        DialogHelper.customToast(getContext(), e.getMessage());
                    }
                });
    }

在这种情况下,不需要使用事务。要将文档从一个位置复制到另一个位置,请使用以下方法:

public void cloneFirestoreDocument(DocumentReference fromPath, final DocumentReference toPath) {
    fromPath.get().addOnCompleteListener(new OnCompleteListener<DocumentSnapshot>() {
        @Override
        public void onComplete(@NonNull Task<DocumentSnapshot> task) {
            if (task.isSuccessful()) {
                DocumentSnapshot document = task.getResult();
                if (document != null) {
                    toPath.set(document.getData())
                        .addOnSuccessListener(new OnSuccessListener<Void>() {
                            @Override
                            public void onSuccess(Void aVoid) {
                                Log.d(TAG, "DocumentSnapshot successfully written!");
                            }
                        })
                        .addOnFailureListener(new OnFailureListener() {
                            @Override
                            public void onFailure(@NonNull Exception e) {
                                Log.w(TAG, "Error writing document", e);
                            }
                        });
                } else {
                    Log.d(TAG, "No such document");
                }
            } else {
                Log.d(TAG, "get failed with ", task.getException());
            }
        }
    });
}
其中,fromPath是要移动的文档的位置,toPath是要移动文档的位置

流程如下:

从fromPath位置获取文档。 将文档写入toPath位置。 根据报告:

如果一个事务读取文档,而另一个客户端修改 对于这些文档,Cloud Firestore将重试事务。此功能 确保事务在最新且一致的数据上运行

因此,如果在事务完成之前对源文档进行了修改,则可以预期事务将重试

您还可以预期事务可能会失败

事务可能因以下原因而失败:

事务包含写入操作之后的读取操作。读取操作必须始终位于任何写入操作之前。 事务读取在事务外部修改的文档。在这种情况下,事务将自动再次运行。 事务重试次数有限。 失败的事务返回一个错误,不向其写入任何内容 数据库。您不需要回滚事务;云 Firestore会自动执行此操作


我会尽快试一试。然而,你能想出我前面的问题不起作用的原因吗?它的作用完全相同,只是在一个事务内部。此外,我认为可能需要一个事务不确定?因为一个用户可能会在文档编写时删除该文档,或者类似的情况。事实并非如此。您正在使用这行代码:setModeMODE\u FOLLOW;具有异步行为的addOnSuccessListener内部。这意味着,在您运行事务时,该行代码尚未调用。请查看以了解事务的用途。请尝试一下,并与我保持联系。谢谢,Doug。如你所见,我不会做那样的事。这就是为什么我很高兴这么简单的交易总是失败,而我有很多复杂的交易从来没有失败过。如果你认为这里有一个bug,请创建一个bug报告并提交一个bug报告。嗯,我不确定,只是想问问有经验的人他们是否看到我的问题code@DougStevenson是否有任何方法在特定重试后中止事务。如果我没有错,事务的最大重试次数是25次。因此,我想知道是否有任何方法可以在5次重试后停止事务。在我的例子中,当事务尝试失败时,不会调用OnFailureListener。