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

Firestore调用FieldValue.increment自增后快速读取数值异常

问题根因

出现重复、跳号不是FieldValue.increment本身的计数bug,是并发场景下独立读写请求的时序不匹配导致的:

  • FieldValue.increment是Firestore提供的原子操作,不管并发多高,服务端最终执行的累加结果一定和总调用次数一致,数据库里存储的t值不会错。
  • 你当前代码里的update累加、get读值是两个完全独立的网络请求,快速连续触发函数时会出现请求排队错位:
    • 前一次调用的update还没在服务端落盘,后一次调用的update已经发出,多个累加操作先后在服务端执行完成,但后续跟进的多个get请求可能命中同一个版本的文档快照,就会打印重复值。
    • 如果某个get请求因网络延迟跳过了中间版本的文档快照,就会出现跳号。
  • 放慢点击速度时,前一次调用的「update落盘 + get拉取最新值」全流程已经走完,下一次调用才发起请求,自然不会出现时序错乱,准确率就会提升。
解决方案

不要在update之后单独发get请求拉取值,直接利用Firestore的实时快照能力同步服务端最新状态,从API层面规避并发时序问题,这是性能和稳定性最优的写法:

// 页面/组件全局初始化一次文档引用即可
final ref = FirebaseFirestore.instance.collection('test').doc('t');

// 点击回调只做原子累加,不单独发起读请求
Future<void> _custom() async {
  await ref.update({'t': FieldValue.increment(1)});
}

// 页面初始化时就注册文档快照监听,服务端值变更时自动同步
@override
void initState() {
  super.initState();
  ref.snapshots().listen((docSnapshot) {
    if (docSnapshot.exists) {
      final currentT = docSnapshot.data()!['t'] as int;
      print(currentT);
      // 此处同步更新页面展示的数值即可
    }
  });
}

如果不想用长连接监听快照,也可以用事务保证读写强一致,适合对一致性要求极高但调用频率不高的场景,性能比原子累加+快照监听稍差:

Future<void> _custom() async {
  await FirebaseFirestore.instance.runTransaction((transaction) async {
    final docSnap = await transaction.get(ref);
    final currentValue = docSnap.data()!['t'] as int;
    final newValue = currentValue + 1;
    transaction.update(ref, {'t': newValue});
    // 事务内拿到的一定是执行完累加的最新值,不会出现时序错位
    print(newValue);
  });
}

不要试图靠客户端加防抖、点击锁来规避这个问题,网络波动时哪怕单次点击也可能出现读写时序错位,从Firestore API特性层面适配才是稳定解法。

内容的提问来源于stack exchange,提问作者Subair K

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.28 00:24:37