Android Kotlin应用中Firestore请求重复导致购买记录重复该如何解决?
问题根因
弱网环境下的更新重复本质是操作不满足幂等性,触发重复执行后就会出现数据异常:
- Firestore SDK默认会对超时/失败的写请求自动重试,如果前一次请求实际已经执行成功只是响应没回到客户端,重试就会导致同一次更新逻辑执行两次
FieldValue.arrayUnion仅会对完全相同的对象去重,如果你的product对象内包含生成时间、临时随机字段等每次调用都会变化的属性,arrayUnion无法识别出是同一次购买的商品,就会重复写入FieldValue.increment本身是累加操作,重复执行就会导致总金额被多次叠加
修复方案
推荐优先使用幂等ID校验+事务的方案,从根本上避免重复执行:
- 每次发起购买流程时,先生成一个全局唯一的幂等ID(如UUID),同一次购买的所有重试都复用同一个ID
- 在客户文档中新增
processedPurchaseIds数组字段,用于存储已经处理完成的购买幂等ID - 改用Firestore事务执行更新,先校验幂等ID是否已存在,存在则直接跳过更新,不存在才执行对应修改并写入幂等ID
示例代码
val db = FirebaseFirestore.getInstance() val clientDocRef = db.collection("client").document(id) // 同一次购买仅生成一次幂等ID,重试时不要重新生成 val uniquePurchaseId = UUID.randomUUID().toString() db.runTransaction { transaction -> val clientSnapshot = transaction.get(clientDocRef) // 读取已处理的幂等ID列表 val processedIds = clientSnapshot.get("processedPurchaseIds") as? List<String> ?: emptyList() // 已处理过直接返回,不做任何修改 if (processedIds.contains(uniquePurchaseId)) { return@runTransaction } // 未处理则执行所有更新操作,同时写入本次幂等ID transaction.update(clientDocRef, hashMapOf( "totalSale" to FieldValue.increment(purchaseValue), "soldProducts" to FieldValue.arrayUnion(product), "processedPurchaseIds" to FieldValue.arrayUnion(uniquePurchaseId) )) }.addOnSuccessListener { // 购买成功后续逻辑 }.addOnFailureListener { // 购买失败后续逻辑,不要在此处重复触发更新请求 }
额外优化建议
- 购买按钮点击后立刻置为不可点击状态,直到更新结果回调返回后再恢复,避免用户弱网下多次点击触发多次更新请求
- 若不需要永久存储幂等ID,可定期清理
processedPurchaseIds数组中30天以上的旧ID,避免文档体积过大
内容的提问来源于stack exchange,提问作者Sebastian Pinzon muñoz
相关产品推荐
相关产品推荐

