首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >如何使用带有Kotlin协同服务的事务在实时数据库中增加计数器?

如何使用带有Kotlin协同服务的事务在实时数据库中增加计数器?
EN

Stack Overflow用户
提问于 2022-09-14 15:48:19
回答 1查看 79关注 0票数 1

要增加实时数据库中的数量,我只需使用:

代码语言:javascript
运行
复制
override fun incrementQuantity() = flow {
    try {
        heroIdRef.update("quantity", FieldValue.increment(1)).await()
        emit(Result.Success(true))
    } catch (e: Exception) {
        emit(Result.Failure(e))
    }
}

而且效果很好。当我需要先检查quantity,然后检查增量时,问题就出现了。上面的解决方案没有帮助,所以我需要使用事务。以下是我尝试过的:

代码语言:javascript
运行
复制
override fun incrementQuantity() {
    val transaction = object : Transaction.Handler {
        override fun doTransaction(mutableData: MutableData): Transaction.Result {
            val quantity = mutableData.getValue(Long::class.java) ?: return Transaction.success(mutableData)
            if (quantity == 1L) {
                mutableData.value = null
            } else {
                mutableData.value = quantity + 1
            }
            return Transaction.success(mutableData)
        }

        override fun onComplete(error: DatabaseError?, committed: Boolean, data: DataSnapshot?) {
            throw error.toException()
        }
    }
    heroIdRef.runTransaction(transaction)
}

但我看不出Kotlin Coroutines是怎么用的。我只想调用await()并返回一个流,如第一个示例所示。我怎么能这么做?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2022-09-15 19:09:57

在这两种情况下,这实际上都不是流的正确使用,因为流用于检索多个串联的事物,但这只返回一件事。它更适合于直接返回该东西的挂起函数。

无论如何,我不是Firebase用户,所以我在这里可能犯了一个错误。看起来他们的Kotlin库没有提供运行事务的挂起函数版本。你可以这样写你自己的作品。这有点混乱,因为完成回调有三个参数,所以我们必须返回一个元组或一个包装类。

代码语言:javascript
运行
复制
data class CompletedTransaction(val error: DatabaseError?, val committed: Boolean, val data: DataSnapshot?)

suspend fun DatabaseReference.runTransaction(
    fireLocalEvents: Boolean = true,
    action: (MutableData)->Transaction.Result
): CompletedTransaction = suspendCoroutine { continuation ->
    val handler = object : Transaction.Handler {
        override fun doTransaction(mutableData: MutableData): Transaction.Result =
            action(mutableData)

        override fun onComplete(error: DatabaseError?, committed: Boolean, data: DataSnapshot?) =
            continuation.resume(CompletedTransaction(error, committed, data))
    }
    runTransaction(handler, fireLocalEvents)
}

然后你就可以:

代码语言:javascript
运行
复制
override suspend fun incrementQuantity(): Result {
    val transaction = heroIdRef.runTransaction { mutableData ->
        val quantity = mutableData.getValue(Long::class.java) ?: return@runTransaction Transaction.success(mutableData)
        mutableData.value = if (quantity == 1L) null else quantity + 1
        Transaction.success(mutableData)
    }
    val failure = transaction.error?.toException()?.let { Result.Failure(it) }
    return failure ?: Result.Success(true)
}

如果由于某种原因需要使用流,则如下所示:

代码语言:javascript
运行
复制
override suspend fun incrementQuantity() = flow {
    val transaction = heroIdRef.runTransaction { mutableData ->
        val quantity = mutableData.getValue(Long::class.java) ?: return@runTransaction Transaction.success(mutableData)
        mutableData.value = if (quantity == 1L) null else quantity + 1
        Transaction.success(mutableData)
    }
    val failure = transaction.error?.toException()?.let { Result.Failure(it) }
    emit(failure ?: Result.Success(true))
}
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/73719810

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档