【问题标题】:Android: How to stop a Firestore transaction?Android:如何停止 Firestore 交易?
【发布时间】:2020-10-14 12:15:56
【问题描述】:

首先,我使用queryWaitingRoom() 查询 Firestore 中的一些文档,如果结果满足条件,则调用 runTransactionInWaitingRoom()

这是第一个函数:

private fun queryWaitingRoom() {
    waitingRoomRef
        .orderBy("isAvailable", Query.Direction.DESCENDING)
        .limit(1)
        .get()
        .addOnSuccessListener { documents ->

            if (!documents.isEmpty){
                for (document in documents) {
                    val waitingRoomId = document.get("id").toString()

                    runTransactionInWaitingRoom(waitingRoomId)
                }
            }
        }
}

我的问题是,在runTransactionInWaitingRoom() 中,如果currentState 的值不等于true,我如何才能在else 块中停止transaction?并再次拨打queryWaitingRoom()? 这是第二个功能:

 private fun runTransactionInWaitingRoom(waitingRoomId: String){
    val docRef = waitingRoomRef.document(waitingRoomId)

    db.runTransaction { transaction ->

        val snapshot = transaction.get(docRef)
        val currentState = snapshot.getBoolean("isAvailable")

        if (currentState == true){
            transaction.update(docRef, "isAvailable", false)
        } else {
            ///// STOP THE TRANSACTION RIGHT HERE /////
            ///// And call the the queryWaitingRoom() again /////

            Log.d("OIWENCLKSJF", "Transaction.currentState != true")   // getting called 5 or 6 times.

            throw FirebaseFirestoreException("Population too high",    // only get called at the last attemp.
                FirebaseFirestoreException.Code.ABORTED)
        }

    }.addOnSuccessListener {

    }.addOnFailureListener { e ->
        Log.w("OIWENCLKSJF", "Transaction failure.", e)
    }
}

到目前为止,我得到的是 transaction 一直在调用自己,即使我将 exception 扔到 else 块中。 我在这里遇到了类似的问题,但没有帮助。如果有人能指导我一点,我将不胜感激。

Firestore how stop Transaction?

【问题讨论】:

  • 请编辑您的问题并将您的数据库结构添加为屏幕截图。除此之外,isAvailable 属性是否与 id 是同一文档的一部分?
  • 我不认为数据库结构与这个问题有任何关系。是的,isAvailable 属性来自同一个文档。同样isAvailable 只能有两个值..truefalse。首次创建时获取true 的值。

标签: android kotlin google-cloud-firestore transactions


【解决方案1】:

是的,isAvailable 属性来自同一个文档。

如果两个属性都属于同一个文档,则仅当isAvailable 属性的值为 true 时才运行事务:

if (!documents.isEmpty){
    for (document in documents) {
        val waitingRoomId = document.get("id").toString()
        val isAvailable = document.getBoolean("isAvailable")
        if(isAvailable) {
            runTransactionInWaitingRoom(waitingRoomId)
        }
    }
}

此解决方案背后的想法是isAvailable 为真时运行事务。你现在在做什么,你总是在运行事务,在里面,如果条件不成立,取消事务。为什么这个解决方案不可行?假设您有 1 MIL 文档,其中只有 1 具有 isAvailable true,您愿意为了一个文档运行 1 MIL 事务吗?恐怕你不是。请记住,在 Firestore 中,执行的每个文档读取都需要一次读取操作。

更好的解决方案是直接在数据库中查询isAvailable 属性值为true 的文档:

waitingRoomRef
    .whereEqualTo("isAvailable", true) //Added
    .orderBy("isAvailable", Query.Direction.DESCENDING)
    .limit(1)
    .get()

在这种情况下,您将直接获得所需的文档。此操作的成本将等于查询返回的文档数。

【讨论】:

  • 我应该更详细地解释它,但即使我使用 .orderBy("isAvailable", true) 这在我的情况下也不起作用。因为在更新isAvailable = false 时,有人可能已经将其值更改为false。然后我又会遇到同样的问题
  • 这是配对系统的一部分。当我将文档的 isAvailable 字段更新为 false 时,这意味着我已经与文档的创建者建立了联系。
  • 有道理。在这种情况下,您应该使用real-time listener,这意味着您会在更改发生时收到通知,然后您可以采取一些措施。您将始终与 Firestore 服务器保持同步。
  • 我在这个系统的其他部分使用了实时监听器,但在这种情况下,我需要使用transaction 读取isAvailable 的值并将其更新为false,因为许多用户可能会得到同一文档并尝试同时将其值更改为false。所以我必须确保只有一个人可以改变它。我在 runTransaction..() 函数中做对了,但是当isAvailable 的值已经更改为false 时,我还没有找到停止transaction 并再次重新运行qurying 的方法由别人。
  • @AlexMamo 提供的第二种解决方案是最好的方法,正如前面提到的,您正在检索您不会使用的文档(您将为此付费)。您可以创建某种队列来侦听实时更改并在需要时将批处理排入队列,不用担心 Firestore 更新太快以至于它会在用户注意到之前完成。使用您的中断交易解决方案,如果您的用户不断在房间之间切换,您可能会发现自己没有完成任何交易。
猜你喜欢
  • 2012-03-05
  • 2018-11-17
  • 1970-01-01
  • 2018-08-13
  • 2020-04-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-09-18
相关资源
最近更新 更多