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

