【发布时间】:2020-01-02 23:44:57
【问题描述】:
我有一个功能是通过交易减少用户对 firebase 实时数据库值的信用。 正如Firebase transaction API call current data is null事务中所建议的那样,当前值偶尔会返回为空。
我已为 null 情况设置了保护并返回 0,因此事务函数再次触发,直到它获得实际信用值。
function charge(cost, description) {
return new Promise((resolve, reject) => {
const creditRef = db.ref(`credits/${userid}`)
ref.transaction(function(current) {
console.log(`${description} current value: ${current}`)
if (current === null) {
console.log(`${description} returns 0 `)
return 0
}
if (cost > current || current === 0) {
//not enough credits return without committing
console.log(`${description} aborts `)
return
}
//commit the new credit value
console.log(`${description} returns ${current} - ${cost}`)
return current - cost
},
(error, commited, snapshot) => {
if (error) {
reject(error)
}
else {
if (commited) {
//user has enough credits
resolve()
}
else {
//not enough credits
reject('no commit')
}
}
})
}
但是,在 2 个充电函数被背靠背触发的情况下,第二次调用将获得当前值 0(这可能是第一次充电调用返回的 0)。因此,假设用户没有足够的积分,它将过早退出。当这两个函数都解析时,最终信用值将是 3,并且第二次收费调用将被忽略。
// User has 5 credits
charge(3, 'first call').then(() => console.log('first call success')
// transaction function returns 0 since current value is null
charge(2, 'second call').then(() => console.log('second call success')
控制台日志输出:
第一次调用当前值:null
第一次调用返回 0
第二次调用当前值:0
第二次通话中止
第一次调用当前值:5
第一次调用返回 5 - 3
第一次调用成功
第二次调用不提交
因此,当用户有足够的积分时,第二次收费电话最终不会通过。 处理firebase事务空值情况的正确方法是什么?
【问题讨论】:
-
我不确定我是否理解问题所在。如果用户没有信用(因为他们的
credits值是0,或者因为他们没有credits的值),他们的交易将被拒绝。如果拒绝结果是错误的(因为数据库中的值已更改),则该函数将被重试。 -
如果您怀疑是
return 0导致了您的问题,我建议您将其替换为不带值的return,看看您是否仍然可以重现该问题。 -
但是如果我使用
return而不是return 0函数将在不提交的情况下完成,当我希望它使用实际的当前值重试时。 (在这种情况下不为空) -
返回没有值会中止事务。见firebase.google.com/docs/reference/js/…
-
正如我所说,我想我不明白这个问题。你能建立一个我可以在某个地方看到的复制品吗?如果这不可行,您能否将您的代码更改为:1)
console.log(current)在开头,2)console.log所有三个return语句的返回值(或缺少),3)编辑您的问题以包括你得到了什么(包括关于哪个客户端/运行记录了哪些行的指示)?
标签: node.js firebase firebase-realtime-database transactions