Flutter中使用Firestore向两个集合新增数据时连续点击计数异常怎么解决
问题根源
- 你当前遇到的数值错误是典型的读-改-写并发冲突:快速点击时多个更新请求会读取到相同的旧统计值,各自累加后写入,最终结果会远小于实际点击次数
- 额外加的Timer不仅没解决根本问题,反而会引发时序错乱,同时降低用户体验
修复方案
1. 替换自定义累加逻辑为Firestore原子增量操作
Firebase提供了FieldValue.increment()原子操作,累加逻辑在服务端执行,天然支持并发场景,不需要你提前读取旧值计算,不会出现冲突。
2. 移除所有Timer延迟逻辑
不需要用延迟控制请求频率,加按钮点击状态控制即可,点击后临时禁用按钮,直到异步操作完成再恢复,避免重复触发。
3. 可选:用事务保证数据一致性
如果需要确保cart子集合和users主集合的更新同时成功/失败,可以把两个操作包裹在Firestore事务中,避免出现数据不一致。
修改后的参考代码
// 记得导入cloud_firestore import 'package:cloud_firestore/cloud_firestore.dart'; // StatefulWidget中定义状态变量控制按钮是否可点击 bool _isAdding = false; !snapshot1.hasData || snapshot1.data!.docs.isEmpty ? InkWell( onTap: _isAdding ? null : () async { _isAdding = true; // 点击后立即禁用按钮 final productDocId = snapshot.data!.docs[index].get('docId'); final productPrice = snapshot.data!.docs[index].get('productPrice'); final uid = snapshot3.data!.docs[0].get('uid'); try { await cartupdate.doc(productDocId).set({ 'docId': productDocId, 'productAmount': 1, 'userId': "WEhxbwBPeI1HIZvIStkM", 'cartTime': DateTime.now(), }); print("product cart added and useramount + 1"); // 用原子增量操作,不需要读旧值计算 await users.doc(uid).update({ 'usercartAmount': FieldValue.increment(1), 'usercheckoutAmount': FieldValue.increment(productPrice) }); } catch (error) { print("Failed to add service: $error"); } finally { _isAdding = false; // 操作完成恢复按钮可点击状态 } }, child: Container( child: Center( child: Icon( Icons.add, size: 35, // 不可点击时置灰图标,给用户明确反馈 color: _isAdding ? Colors.grey : null, ), ) ) ) : InkWell( onTap: _isAdding ? null : () async { _isAdding = true; final productDocId = snapshot.data!.docs[index].get('docId'); final productPrice = snapshot.data!.docs[index].get('productPrice'); final uid = snapshot3.data!.docs[0].get('uid'); try { // 购物车已有商品,直接原子累加购买数量 await cartupdate.doc(productDocId).update({ 'productAmount': FieldValue.increment(1), }); print("product amount +1"); await users.doc(uid).update({ 'usercartAmount': FieldValue.increment(1), 'usercheckoutAmount': FieldValue.increment(productPrice) }); } catch (error) { print("Failed to add service: $error"); } finally { _isAdding = false; } }, child: Container( child: Center( child: Icon( Icons.add, size: 35, color: _isAdding ? Colors.grey : null, ), ) ) )
内容的提问来源于stack exchange,提问作者Arminmos
相关产品推荐
相关产品推荐

