gpt4 book ai didi

javascript - Firebase并发修改和事务解决方案

转载 作者:行者123 更新时间:2023-11-30 14:45:53 25 4
gpt4 key购买 nike

我有一个 Android 应用程序(游戏),可以匹配 2 个人并让他们玩。我正在为此使用 firebase 实时数据库,并在 Node.js 上为此编写了必要的代码。在我的数据库中,当有人点击“在线按钮”时,它会触发 firebase 功能并使玩家状态等待(状态:WAITING)并将他/她与另一个状态也为“等待”的玩家匹配,如果操作成功 node.js 更新“rakip”节点,其中包含双方玩家的对手用户名,以便进行进一步操作。

但是我担心的是当 2 个用户同时搜索对手时(假设用户 A 和 B)可能会出现糟糕的情况,例如用户 A 与 B 匹配,用户 B 与 C 匹配。我该如何防止这会发生吗?如何在他/她的状态发生变化时立即停止 B 的搜索(node.js 操作)?

提前致谢。

我的实时 firebase 数据库是这样的:

My-project-name
users
sinan
atilansayi: ""
gal: false
lose: 0
rakip: "hakan"
rakipsallama: ""
sayilar: "4567"
sonuc: ""
status: "on"
turn: false
win: 1
hakan
atilansayi: 5678
gal: false
lose: 1
rakip: "sinan"
rakipsallama: "7559|13238436"
sayilar: 7559
sonuc: "-"
status: "on"
turn: true
win: 0
mehmet
atilansayi: 9000
gal: "no"
lose: 0
rakip: "hakan"
rakipsallama: 3333
sayilar: 7000
sonuc: "+"
status: "on"
turn: false
win: 0

我的 Node.js 文件是:

const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp(functions.config().firebase);

exports.sayi = functions.database.ref("/users/{uid}/status").onWrite(event => {
var status = event.data.val();
var user = event.data.ref.parent.key;
if (status ==="waiting") {
const events = admin.database().ref('users');
const query =events.orderByChild('status').equalTo('waiting').limitToFirst(2);
query.on("value",
function(data) {
var waitinggameusers= data.val();
var keys = Object.keys(waitinggameusers);
for (var i = 0; i < keys.length; i++) {
var key = keys[i];
if(key!==user){

/////////////这是可能出现问题的部分////////////////

                    admin.database().ref("/users/"+user+"/rakip").set(key);
admin.database().ref("/users/"+key+"/rakip").set(user);
admin.database().ref("/users/"+user+"/status").set("on");
admin.database().ref("/users/"+key+"/status").set("on");
return console.log("bbbb"+" "+key);

/////////////这是可能出现问题的部分////////////////

                }               
}
}, sorunlu);
}
});
exports.sayiat = functions.database.ref("/users/{uid}/atilansayi").onWrite(event => {
var sallanansayi ="";
var rakibinsayisi ="";
var res = event.data.val();
if(res===""){
return true;
}
var res2 = res.split("|");
sallanansayi += res2[0];
sallanansayi2=sallanansayi;
var user = event.data.ref.parent.key;
var sonuc ="";
var artilar ="";
return admin.database().ref('users/'+user+'/rakip').once('value').then(function(snapshot){
var rakip = snapshot.val();
console.log("Rakip: "+rakip);
return admin.database().ref('users/'+rakip+'/sayilar').once('value').then(function(sayisinibul){
rakibinsayisi += sayisinibul.val();
for (i = 0; i < sallanansayi2.length; i++) {
if(sallanansayi2.charAt(i)===rakibinsayisi.charAt(i)){
sonuc +="+";
artilar += i;
}
}
console.log("Sonuç(sadece artılar): "+sonuc);
console.log("Artıların yerleri: "+artilar);
console.log("Artiların sayısı: "+artilar.length);
for (i = 0; i < artilar.length; i++) {
sallanansayi2 = sallanansayi2.slice(0, artilar.charAt(i)) +"a"+ sallanansayi2.slice(Number(artilar.charAt(i))+1);
rakibinsayisi = rakibinsayisi.slice(0, artilar.charAt(i)) +"b"+ rakibinsayisi.slice(Number(artilar.charAt(i))+1);
}
console.log("Atılan sayı: "+sallanansayi2);
console.log("Rakibin sayısı: "+rakibinsayisi);
for (i = 0; i < sallanansayi2.length; i++) {
if(rakibinsayisi.indexOf(sallanansayi2.charAt(i))!==-1){
sonuc += "-";
var x= rakibinsayisi.indexOf(sallanansayi2.charAt(i));
rakibinsayisi= rakibinsayisi.slice(0,x)+"y"+rakibinsayisi.slice(x+1);
sallanansayi2= sallanansayi2.slice(0,i)+"x"+sallanansayi2.slice(i+1);
}
}
var randomnumber = getRndInteger(1,100000000);
if(sonuc===""){
sonuc ="x";
}else if(sonuc==="++++"){
admin.database().ref('users/'+user+'/win').transaction(count => {
if (count === null) {
return count = 1
} else {
return count + 1
}
})
admin.database().ref('users/'+rakip+'/lose').transaction(count => {
if (count === null) {
return count = 1
} else {
return count + 1
}
})
admin.database().ref("/users/"+user+"/turn").set(false);
admin.database().ref("/users/"+rakip+"/turn").set(true);
admin.database().ref("/users/"+user+"/sonuc").set(sonuc+"|"+randomnumber);
return admin.database().ref("/users/"+rakip+"/rakipsallama").set(sallanansayi+"|"+randomnumber);
//return admin.database().ref("/users/"+user+"/gal").set(true);
}
console.log("Rakibin sayısı(son): "+rakibinsayisi);
console.log("Sallanan sayı(son): "+sallanansayi2);
console.log("Sonuç: "+sonuc);
admin.database().ref("/users/"+user+"/turn").set(false);
admin.database().ref("/users/"+rakip+"/rakipsallama").set(sallanansayi+"|"+randomnumber);
admin.database().ref("/users/"+rakip+"/turn").set(true);
return admin.database().ref("/users/"+user+"/sonuc").set(sonuc+"|"+randomnumber);
});
});
});


function sorunlu(error) {
console.log("Something went wrong.");
return console.log(error);
}
function getRndInteger(min, max) {
return Math.floor(Math.random() * (max - min) ) + min;
}

/////

Frank 的数据库规则建议与读/写访问相结合

{
"rules": {
"users": {
"$uid": {
".read": "auth.uid == $uid",
".write": "auth.uid == $uid",
"status": {
".validate": "newData.val() === 'on' || data.val() === 'off'|| data.val() === 'waiting'"
},
"rakip": {
".validate":
"newData.parent().parent().child(newData.val()).child('rakip').val() === $uid"
}
}
}
}
}

最佳答案

这里加强一致性的最佳方法似乎是使用多位置更新。通过多位置更新,您可以在一次调用中向服务器发送多个更新,并且服务器会强制执行所有写入,或者都不发生。

您的代码片段:

admin.database().ref("/users/"+user+"/rakip").set(key);
admin.database().ref("/users/"+key+"/rakip").set(user);
admin.database().ref("/users/"+user+"/status").set("on");
admin.database().ref("/users/"+key+"/status").set("on");

可以重写为单个多位置更新:

var updates = {};
updates["/users/"+user+"/rakip"] = key;
updates["/users/"+key+"/rakip"] = user;
updates["/users/"+user+"/status"] = "on";
updates["/users/"+key+"/status"] = "on";
admin.database().ref().update(updates);

现在在服务器上您可以使用安全规则来确保原始数据未被修改。

如果你只能将状态设置为 "on",如果它当前是 "off",你将在 /users/$user/status 上验证:

".validate": "newData.val() === 'on' && data.val() === 'off'"

还有一个更棘手的问题:确保您只能设置 "rakip" 值,前提是该用户的值也已设置 validate /users/$user/rakip:

".validate": "newData.parent().parent().child(newData.val()).child('rakip').val() === $user"

综合这些是:

{
"rules": {
"users": {
"$user": {
"status": {
".validate": "newData.val() === 'on' && data.val() === 'off'"
},
"rakip": {
".validate": "newData.parent().parent().child(newData.val()).child('rakip').val() === $user"
}
}
}
}
}

关于javascript - Firebase并发修改和事务解决方案,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48940012/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com