【问题标题】:how to handle null values on firebase transaction api如何处理firebase事务api上的空值
【发布时间】: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


【解决方案1】:

如果您从数据库中获得null,则不应进行任何更改。既然你得到了null,也返回null

所以:

const ref = firebase.database().ref(`59571450`)
function charge(cost, description) {
  return new Promise((resolve, reject) => {
    ref.transaction(function(current) {
      console.log(`${description} current value: ${current}`);
      if (current === null) {
        console.log(`${description} returns null`)
        return null;
      }
      if (cost > current) {
        //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')
        }
      }
    });
  });
}
                     

ref.set(5).then(() => {
  charge(3, 'first call').then(() => console.log('first call success'))
  charge(2, 'second call').then(() => console.log('second call success'))
})

运行时会给出以下输出:

第一次调用当前值:null

第一次调用返回 null

第二次调用当前值:null

第二次调用返回 null

第一次调用当前值:5

第一次调用返回 5 - 3

第二次调用当前值:2

第二次调用返回 2 - 2

第一次调用成功

第二次通话成功

有关此代码的工作版本,请参阅:https://jsbin.com/xefebul/1/edit?js,console

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-01-14
    • 2021-03-26
    • 2019-06-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多