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

如何实现Firebase Firestore与Storage同步删除 异常时均不删除

问题根因

你当前的串行删除逻辑完全没有一致性保护,两个操作分别是独立的网络请求:只要图片删除成功后、笔记文档删除前出现任何异常(网络闪断、权限校验失败、服务端临时错误),就会出现「图片已经被删但笔记残留」的脏数据,根本达不到两个资源要么同时删除成功、要么全部保留的要求。

实现思路

Firebase Storage的文件操作和Firestore的文档操作不在同一个原生事务支持范围内,没法直接用单事务包裹两个操作实现原子性,工业界通用的解法是用「软删除标记+失败回滚+定时兜底重试」的方案,完全规避中间态问题:

  • 第一步:删除操作触发时,不要直接硬删任何真实资源,先通过单文档原子更新给目标笔记打上pendingDelete待删除标记,同时记录关联的所有图片地址、操作触发时间。这步要么成功要么直接失败,不会产生中间状态。
  • 第二步:待标记写入成功后,再依次执行关联图片删除、笔记硬删除操作。
    • 两个操作全部执行成功,删除流程正常结束。
    • 任意环节抛出错误,立刻执行回滚:清除笔记上的待删除标记,把笔记恢复为正常可见状态;如果已经有部分图片被误删,就从备份存储回拷对应文件,保证笔记内容完整可用。
  • 第三步:配置定时触发的云函数,定期扫描带pendingDelete标记且超过超时阈值(建议设为5-10分钟)的笔记,自动重试剩余的删除步骤,避免临时故障导致删除流程卡死、资源残留。
参考实现代码
Future<void> deleteNote(QueryDocumentSnapshot noteSnapshot) async {
  final targetNoteId = noteSnapshot.id;
  final linkedImageUrl = noteSnapshot['imageURL'] as String;
  final imageRef = FirebaseStorage.instance.refFromURL(linkedImageUrl);
  final noteDocRef = notesReference.doc(targetNoteId);

  try {
    // 原子写入待删除标记,这步失败直接终止流程,不会改动任何资源
    await noteDocRef.update({
      'pendingDelete': true,
      'deleteTriggerTime': FieldValue.serverTimestamp(),
    });

    // 删除关联存储图片
    await imageRef.delete();

    // 硬删除笔记文档
    await noteDocRef.delete();

  } catch (err) {
    // 任意步骤出错立刻回滚,清除待删除标记恢复笔记
    // 若业务要求高一致性,可在此处添加已删图片的恢复逻辑
    await noteDocRef.update({
      'pendingDelete': FieldValue.delete(),
      'deleteTriggerTime': FieldValue.delete(),
    });
    // 可按需将错误抛到上层,给用户弹出删除失败提示
    rethrow;
  }
}
落地注意事项
  • 不要调换删除顺序先删笔记再删图片,否则会出现笔记已经消失但存储图片残留的问题,长期累积会浪费大量存储额度。
  • 正常的笔记列表查询逻辑要加上where('pendingDelete', isEqualTo: false)过滤条件,避免待删除的笔记展示给用户。
  • 如果单条笔记关联多张图片,软删除阶段要把所有图片的URL都记录到笔记字段中,只有全部图片删除成功才执行笔记硬删,只要任意一张图片删除失败就全量回滚。

内容的提问来源于stack exchange,提问作者Esraa Hamada

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.27 06:24:25