简体   繁体   English

Firebase - 实时数据库中 2 个路径的一个事务

[英]Firebase - One transaction for 2 paths in real time database

I have a database with the following structure:我有一个具有以下结构的数据库:

我的数据库结构

Now two paintings can be rated against each other and the rating is then updated.现在可以对两幅画进行评分,然后更新评分。 But it can happen that one painting is rated mutliple times at the same time.但可能会发生一幅画同时被多次评级的情况。 Therefore i tried using a nested transaction (see below) to avoid race conditions:因此我尝试使用嵌套事务(见下文)来避免竞争条件:

function pictureClicked(picture) {
    const db = getDatabase();
    const leftRef = ref(db, '/paintings/' + generateDbName(currentLeft));
    const rightRef = ref(db, '/paintings/' + generateDbName(currentRight));
    const winnerLeft = (picture === 'left') ? 1 : 0;

    runTransaction(leftRef, (leftP) => {
        if (leftP) {
            runTransaction(rightRef, (rightP) => {
                if (rightP) {
                    // Calculation of the new rating for each painting (Elo System)
                    const tRatingLeft = Math.pow(10, leftP.rating / 400);
                    const tRatingRight = Math.pow(10, rightP.rating / 400);

                    const expectedLeft = tRatingLeft / (tRatingLeft + tRatingRight);
                    const expectedRight = tRatingRight / (tRatingLeft + tRatingRight);

                    // Setting new rating
                    leftP.rating = leftP.rating + 32 * (winnerLeft - expectedLeft);
                    rightP.rating = rightP.rating + 32 * ((1 - winnerLeft) - expectedRight);
                }
                return rightP;
            });
        }
        return leftP;
    });
}

Now this solution doesn't really work and I have read that it isn't the best approach to this problem.现在这个解决方案并没有真正起作用,我已经读到它不是解决这个问题的最佳方法。 The only solution I found was running a transaction on the root of my database but I'm afraid that this would lead to a bottleneck and many of the launched transactions wouldn't even write to the database since transactions are only retried 25 times (or is my fear here unfounded?).我找到的唯一解决方案是在我的数据库的根目录上运行一个事务,但我担心这会导致瓶颈并且许多启动的事务甚至不会写入数据库,因为事务只重试了 25 次(或我在这里的恐惧是没有根据的吗?)。 Are there any other solutions to this problem?这个问题还有其他解决方案吗?

Firebase Realtime Database transactions run against a single path in your database. Firebase 实时数据库事务针对数据库中的单个路径运行。 There is currently no way to run a transaction against multiple path, so the common approach is to run the transaction against the lowest-level shared path ( /paintings in your case).目前没有办法针对多个路径运行事务,因此常见的方法是针对最低级别的共享路径( /paintings在您的情况下)运行事务。

This can indeed lead to more contention as you have more users performing concurrent transactions.这确实会导致更多的争用,因为您有更多的用户执行并发事务。


The only alternative I've used at times is to build my own transaction mechanism using:我有时使用的唯一替代方法是使用以下方法构建我自己的事务机制:

  1. Multi-path updates, to perform both writes at the same time.多路径更新,同时执行两个写入。
  2. Security rules, to only allow the transition that make sense in my use-case.安全规则,只允许在我的用例中有意义的转换。
  3. Client-side retries, so that contention or outdated data are still handled correctly.客户端重试,以便仍然正确处理争用或过时的数据。

This is fairly non-trivial even for simple cases, and may require changing your data structure and/or adding additional values to each request.即使对于简单的情况,这也是相当重要的,并且可能需要更改您的数据结构和/或为每个请求添加额外的值。 But if you get past those hurdles, it will allow you to run a "transaction" across multiple paths.但是,如果您克服了这些障碍,它将允许您跨多个路径运行“交易”。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM