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

Firestore事务条件更新异常:读取文档未写入报错

Firestore事务条件更新的问题解答

首先明确回答:Firestore事务完全支持条件更新,你遇到的异常是因为违反了Firestore事务的核心规则——在事务中读取的每一个文档,必须在事务中被写入(无论条件是否满足)。

为什么会触发这个异常?

你的代码逻辑是:读取文档后,只有当displayedUser和userName匹配时才执行更新,不匹配时就什么都不做。但Firestore的事务机制要求,只要你在事务中读取了某个文档,就必须对它执行写入操作(哪怕是写入和当前值完全相同的内容)。这是因为事务会锁定读取的文档,若没有写入操作,Firestore会认为这是一个无意义的事务,浪费资源,因此抛出Every document read in a transaction must also be written异常。

解决方案

这里有两种简洁的方案,根据你的场景选择:

方案1:在不满足条件时执行"空写入"

既然事务要求读必写,那我们可以在条件不匹配时,写入当前文档的原有值(相当于没有实际修改,但满足了事务的写入要求)。修改后的代码如下:

// update toolbar titles if they match
final DocumentReference adminDocRef = mDbase.collection("admins").document(adminID);
mDbase.runTransaction(new Transaction.Function<Void>() {
    @Override
    public Void apply(@NonNull Transaction transaction) throws FirebaseFirestoreException {
        DocumentSnapshot adminSnapshot = transaction.get(adminDocRef);
        String toolbarTitle = adminSnapshot.getString("displayedUser");
        
        if (userName.equals(toolbarTitle)) {
            transaction.update(adminDocRef, "displayedUser", userName);
        } else {
            // 写入原有值,满足事务的"读必写"要求
            transaction.update(adminDocRef, "displayedUser", toolbarTitle);
        }
        
        return null;
    }
})
.addOnSuccessListener(new OnSuccessListener<Void>() {
    @Override
    public void onSuccess(Void aVoid) {
        Log.d(TAG, "Transaction success!");
    }
})
.addOnFailureListener(new OnFailureListener() {
    @Override
    public void onFailure(@NonNull Exception e) {
        Log.w(TAG, "Transaction failure.", e);
    }
});

方案2:改用带条件的直接更新(无需事务)

如果你的条件逻辑比较简单(比如只需要判断某个字段等于特定值),可以直接使用Firestore的条件更新API,不需要启动事务。Firestore会自动原子性地检查条件并执行更新,代码更简洁:

mDbase.collection("admins")
    .document(adminID)
    // 添加条件:只有当displayedUser等于userName时才执行更新
    .whereEqualTo("displayedUser", userName)
    .update("displayedUser", userName)
    .addOnSuccessListener(new OnSuccessListener<Void>() {
        @Override
        public void onSuccess(Void aVoid) {
            Log.d(TAG, "Update success (if condition matched)!");
        }
    })
    .addOnFailureListener(new OnFailureListener() {
        @Override
        public void onFailure(@NonNull Exception e) {
            Log.w(TAG, "Update failure.", e);
        }
    });

这种方式的优势是不需要手动管理事务,Firestore在底层处理原子性,而且避免了"读必写"的限制。不过如果你的条件逻辑涉及多个字段读取或复杂判断,还是需要用事务+方案1的方式。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.28 07:03:51