Firebase v9 Firestore 依次写入两个文档的错误处理与一致性实现方案
解决方案
要实现两个文档的原子写入(要么同时成功要么全部失败),同时解决竞态问题和完善错误处理,推荐使用Firebase v9 Firestore提供的**事务(Transaction)**能力,改写后的代码如下:
import { runTransaction } from "firebase/firestore"; try { const result = await runTransaction(db, async (transaction) => { // 写入第一个product文档 transaction.set(product, docData, { merge: true }); // 读取products_array文档,根据存在状态执行对应写入逻辑 const productsArraySnap = await transaction.get(products_array); if (productsArraySnap.exists()) { transaction.update(products_array, { products_array: arrayUnion(productSKU) }); console.log("Product array exists:", productsArraySnap.data()); } else { transaction.set(products_array, { products_array: arrayUnion(productSKU), products_default: productSKU }); console.log("No product array, initialized new record"); } return "两个文档写入成功"; }); console.log(result); // 此处补充写入成功后的业务逻辑 } catch (e) { console.error("写入失败,所有操作已回滚:", e); // 此处补充错误处理逻辑,比如用户提示、错误上报等 }
方案说明
- 原子性保证:事务中的所有写入操作会在提交时统一执行,只要有一个操作失败,整个事务会自动回滚,不会出现第一个文档写入成功、第二个失败的不一致情况
- 竞态解决:事务中对
products_array文档的读取和写入是原子绑定的,Firebase会自动检测并发修改冲突,默认最多重试5次,避免先读再写的逻辑在高并发下出现数据异常 - 错误处理:通过外层
try/catch统一捕获所有异常,包括事务失败、权限错误、网络问题等,可直接在catch分支做统一异常处理
如果你的业务场景不需要先读取products_array文档的内容做判断,也可以使用更轻量的**批写入(Batch Write)**实现:
import { writeBatch } from "firebase/firestore"; try { const batch = writeBatch(db); // 写入第一个文档 batch.set(product, docData, { merge: true }); // 写入第二个文档,set配合merge实现不存在则创建、存在则更新的效果 batch.set(products_array, { products_array: arrayUnion(productSKU), products_default: productSKU }, { mergeFields: ["products_array"] }); // 提交批写入 await batch.commit(); console.log("两个文档写入成功"); } catch (e) { console.error("写入失败,所有操作已回滚:", e); }
内容的提问来源于stack exchange,提问作者awariat
相关产品推荐
相关产品推荐

