【问题标题】:Transaction only works once with simultaneous calls事务仅适用于同时调用一次
【发布时间】:2019-08-31 17:38:13
【问题描述】:

我们在应用程序中使用下面的代码来执行对数据库的写入。但是,多个客户端可能同时在写入,所以我们使用了Transaction,因为如果在执行期间数据被另一个Transaction 修改,它应该会再次运行。 不过似乎出了点问题:当单独的客户端(两个不同的移动设备)同时运行下面的代码时,似乎只有一个客户端更新了数据库中的值。

这可能是什么原因造成的,我们将来如何防止这种情况发生?

  static Future< bool > voteOnUser(GroupData groupData, String voteeID) async {

    await Firestore.instance.runTransaction((Transaction transaction) async {
      DocumentReference groupRef = Firestore.instance
                                    .collection("groups")
                                    .document( groupData.getGroupCode() );

      DocumentSnapshot ds = await transaction.get( groupRef );

      /// Initialize lists
      Map<dynamic, dynamic> dbData = ds.data['newVotes'];
      Map<String, int> convertedData = new Map<String, int>();

      /// Loop the database Map and add the values to the data Map
      /// All data is assumed to exist and definitely be of the desired types
      dbData.forEach( (key, value) {
        convertedData[key.toString()] = value;
      } );

      if (convertedData.containsKey( voteeID ))
        convertedData[voteeID] += 1;
      else convertedData[voteeID] = 1;

      Map<String, dynamic> incremented = new Map<String, dynamic>();
      incremented['newVotes'] = convertedData;

      await transaction.update(groupRef, incremented);

    });

    return true;

  }

编辑:此代码的目的是对位于文档内地图中的用户进行投票。多个客户端可以同时投票,每次投票应该将地图中一个元素的值加一。 当两个客户端同时对例如之前没有投票的 ID 为“joe”的用户进行投票时,预期的结果是 joe 将获得两票。但是,在测试同时投票时,我们观察到数据库中只添加了一票,而不是期望的两票。

编辑 2:首先,该文档存在并且包含一个空映射 newVotes。我们正在使用两种不同的移动设备进行测试,并在±同一时间点投票。几乎立刻,文档就被更新了,并且一个用户 ID 被添加到之前为空的映射中,只需一票,而我们预计两票会映射到该键。

编辑 3:首先,创建一个包含以下字段的文档:newVotes (map) 将投票数映射到唯一的用户 id,totalVotes (map) 跟踪总数投票和成员(列表),这是该组中所有用户 ID 的列表。 newVotes 和 totalVotes 此时为空,且 members 包含一些 ID(在本例中,是两个唯一的 Google ID) 一旦此文档存在,客户就可以使用给定的代码进行投票。在我的例子中,我们都对同一个谷歌用户 ID(比如:“ID1”)进行了投票,并希望地图 newVotes 包含一个元素:{“ID1”:2}。但是,我们同时投票(没有引发错误),并且 newVotes 字段包含 {"ID1":1}。

【问题讨论】:

  • 请编辑问题以准确解释您所观察到的不符合您预期的情况。
  • 我编辑了这个问题,希望这次我把我的问题说清楚了。
  • 你能说得更具体点吗?在执行代码之前,文档究竟包含什么?后面包含什么?这与预期的内容有何不同?
  • 我添加了另一个编辑,应该澄清一些事情。
  • 1) 您是否锁定了该实体以读取显性? 2) Optimistic lockig (version controll) 就是你要找的。​​span>

标签: firebase dart google-cloud-firestore


【解决方案1】:

Transactions 不保证防止同时修改同一实体 - 除非 SERIALIZED(或“读取更新锁定”)。它保证事务中的每个操作都将在commit 上立即应用,如果tx 为rolled back 则丢弃

为了保证也没有冲突:

  1. 同步访问实体 - 读取时锁定
  2. 同步方法执行
  3. 序列化交易
  4. 使用版本控制机制

【讨论】:

猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-08
  • 1970-01-01
  • 2011-03-08
  • 1970-01-01
  • 1970-01-01
  • 2023-04-03
相关资源
最近更新 更多