我有一个包含整个用户产品的集合,并且为了避免阅读所有档案以获得集合的长度,我在创建档案后为每个栏位增加一个值 1,好的,现在一切正常
在这里,我使用这种方法来判断档案是否存在,这样我可以避免在离线模式下重复计数器
removeProduct1(){
FirebaseFirestore.instance.collection("product").doc('product1')
.get(const GetOptions(source: Source.server)).then((value1) {
if(value1.exists) {
FirebaseFirestore.instance.collection("product").doc('product1').delete();
FirebaseFirestore.instance.collection("product").doc('productCount').update({
'productCount': FieldValue.increment(-1),
});
}
}).onError((error, stackTrace) {
ScaffoldMessenger.of(context).showSnackBar(snackBar,);
});
}
也一切正常,但我注意到如果两个用户同时按下此方法的按钮,那么它会减少两个值 -2 也许有人会认为当两个用户同时按下按钮时它很少,嗯,这是只是我真正拥有的简单示例,我的页面包含太多用户,这对于两个用户点击按钮并不罕见
编辑 MOER 解释
我有一个名为的集合Friends
,其中包含朋友的用户 ID,例如 user1 他的 id 是ABC
,user2 他的 id 是所以 id通过关注DEF
变成最终的Friends collection
这样的,
并且接下来的每一个都增加计数器 1ABCDEF
function
function
makeFriends(){
// here i make sure first if the friends Ids are not exists To avoid suspiciously increasing the counter in offline mode and its work very well
FirebaseFirestore.instance.collection("Friends").doc(user1Id user2Id).get().then((value) {
if(!value.exists){
// here to add ids to the friends collection
FirebaseFirestore.instance.collection("Friends").doc(user1Id user2Id).set({
'test':''
});
//here to increase counter in other colection which is users for both user
//user1
FirebaseFirestore.instance.collection("users").doc(user1Id).update({
'friendsCounter':FieldValue.increment(1)
});
//user2
FirebaseFirestore.instance.collection("users").doc(user2Id).update({
'friendsCounter':FieldValue.increment(1)
});
}
});
}
好的,现在一切顺利,他们成为了朋友,价值增加了??,他们的 ID 成为朋友收藏的单位 .. 这里的图片可以更好地解释
图 1
图片
在这里,我有function
责任洗掉FriendsCount Field
他们两个都减少一个值的朋友
deleteFriends(){
// here i make sure first if the friends Ids are exists To
// avoid suspiciously decrease the counter in offline mode and its work very well
FirebaseFirestore.instance.collection("Friends").doc(user1Id user2Id).get().then((value) {
if(value.exists){
// here to remove ids from the friends collection
FirebaseFirestore.instance.collection("Friends").doc(user1Id user2Id).delete();
//here to decrease counter for both user
//user1
FirebaseFirestore.instance.collection("users").doc(user1Id).update({
'friendsCounter':FieldValue.increment(-1)
});
//user2
FirebaseFirestore.instance.collection("users").doc(user2Id).update({
'friendsCounter':FieldValue.increment(-1)
});
}
});
}
ok now also everything going fine .. lets say user1 deleted his friend user 2 , by the previous function
the Friends id which is ABCDEF
has been deleted so next time if user 2 want to do the same opretion it will fail because Friends ids are not exist anymore ..
the problem IS :
lets say these two users are still friends and
these two user visited each others profiles and hit the button at the same time which is call the pervious function
(deleteFriend) so they gonna get the same return value which is (yes exists) then will be double decrease value for both of them instead of one as required .
means if their friendsCount
was 1 both of them when they was a friend so tee value will be -1 instead 0 because there two operation was proceed
and this happen only if these two user hit the button at the same moment , but if the user 1 hit the button before user 2 then user 2 want to do same operation so he ganna fail because friendId
was deleted by user1 operation as a condition statement in previous function ..
if(value.exists) i thought it too fast to delete friendIds before it give same result to other user if they together call the function at the same time
of course i can prevent the button of calling the delete function in case one of these user is already deleted other but I didn't see this as a strong solution since i can't grantee traffic jam or any reason else like bad users behavior .. etc , also basically i can't do it because delete button must be available as long as they still a friends
Note: this also happen in addFriends buttom call too if two users hit it at the same time , double value 2 instead one ..
如果有两个用户同时查询相同的档案,或者任何好的解决方案,我需要任何方法来避免服务器给出相同的结果
uj5u.com热心网友回复:
如果您需要读取和写入档案来更新它,您应该使用事务来防止当多个用户几乎同时执行操作时出现的竞争条件。
在这里你肯定要使用事务,因为如果洗掉由于某种原因失败,减量操作也应该失败(反之亦然)。
FlutterFire 关于事务的档案也有很好的解释和示例代码以供入门。
0 评论