使用Firebase模拟器时,FireStore事务意外触发onUpdateProfile云函数
FireStore事务意外触发Profile文档更新的原因分析
问题背景
项目后端采用FireStore、Cloud Functions与Firebase模拟器,前端使用Flutter。通过FireStore事务读取用户Profile文档,仅用该文档数据创建两个关联文档,但Firebase模拟器日志显示onUpdateProfile云函数被触发(说明Profile文档被更新),但代码中并未对该文档执行任何更新操作。改用批量操作(先读取Profile文档,再通过批量写入创建关联文档)后,Profile文档未再被更新。
事务代码
await _firestore.runTransaction((transaction) async { // 先在事务内读取profile,注意这里没有更新profile final docSnapshot = await transaction.get(_firestore.doc('/users/$id')); final profile = docSnapshot.data(); if (profile != null) { // 从profile中获取需要的数据 final pName = profile['name'] as String; // 创建两个关联文档 transaction ..set(_firestore.doc('/users/$uid/relationships/$pid'), { 'authorId': uid, 'pName': pName // 省略其他属性 }) ..set(_firestore.doc('/users/$pid/relationships/$uid'), { 'authorId': uid, 'pName': myProfile.name // 省略其他属性 }); } });
批量操作代码
// 先从FireStore读取profile文档 final docSnapshot = await _firestore .doc('/users/$pid') .withConverter<MyProfile>( fromFirestore: MyProfile.fromFirestore, toFirestore: (myProfile, _) => myProfile.toFirestore(), ) .get(); final profile = docSnapshot.data(); // 用批量写入创建两个关联文档 final batch = _firestore.batch() ..set(_firestore.doc('/users/$uid/relationships/$pid'), { 'authorId': uid, 'pName': profile.name, // 省略其他属性 }) ..set(_firestore.doc('/users/$pid/relationships/$uid'), { 'authorId': uid, 'pName': myProfile.name, // 省略其他属性 }); await batch.commit();
Firebase模拟器日志
i functions: Beginning execution of "us-east4-onCreateRelationship" i functions: Finished "us-east4-onCreateRelationship" in 2.332654ms i functions: Beginning execution of "us-east4-onCreateRelationship" i functions: Finished "us-east4-onCreateRelationship" in 371.116441ms i functions: Beginning execution of "us-east4-onUpdateProfile". <---------- i functions: Finished "us-east4-onUpdateProfile" in 2.047866ms <----------
原因分析
这是FireStore事务的乐观锁机制导致的“伪更新”触发:
- 当你在事务中读取文档时,FireStore会记录该文档的当前版本号(ETag)。事务提交阶段,FireStore会验证所有被读取的文档在事务执行期间是否被外部修改——只有未被修改,才会提交事务内的写入操作。
- 在Firebase模拟器(甚至部分生产环境场景)中,这个版本验证流程可能被误识别为一次“文档更新”,进而触发
onUpdateProfile触发器。本质上事务并未修改Profile文档的内容,但事务的「读取-验证-提交」流程让FireStore认为文档有版本变更。 - 批量操作没有事务的版本验证机制:它只是独立的“先读再写”操作,不会对原文档做版本标记或验证,因此不会触发更新触发器。
另外可以检查onUpdateProfile触发器的监听范围,确认是否误将/users下的子集合变更纳入监听,但从日志明确触发onUpdateProfile来看,核心原因还是事务的版本验证机制导致的触发器误触发。
内容的提问来源于Stack Exchange,提问作者Aimn Blbol
相关产品推荐
相关产品推荐

