【问题标题】:Firestore transaction fails with "Transaction failed all retries"Firestore 事务失败并显示“事务所有重试失败”
【发布时间】:2018-06-21 19:08:10
【问题描述】:

我正在运行一个非常简单的 Firestore 事务,它会检查文档是否存在,如果不存在则写入它。

(用例正在注册用户名 - 如果尚未注册,则当前用户可以获取它)

这是相关 Flutter 代码的 sn-p:

DocumentReference usernameDocRef =
    Firestore.instance.collection(_USERNAMES).document(username);

await Firestore.instance.runTransaction((transaction) async {
  var snapshot = await transaction.get(usernameDocRef);
  if (!snapshot.exists) {
    transaction.set(usernameDocRef, {
      _UsernamesKey.userid: _user.id,
    });
  }
});

这失败了,出现“事务所有重试失败”异常。

基于Firestore documentation,失败可能有两个原因:

  • 事务包含写操作之后的读操作。读取操作必须始终在任何写入操作之前进行。
  • 事务读取了在事务之外修改的文档。在这种情况下,事务会自动再次运行。事务被重试有限次。

我认为我不会触发其中任何一个。有什么建议吗?

【问题讨论】:

  • 我提出了一个关于这个的问题:github.com/flutter/flutter/issues/18747
  • 终于可以解决问题了吗?
  • 交易也可能由于规则(身份验证)问题而失败,在这种情况下您应该收到403 错误。

标签: firebase transactions google-cloud-firestore flutter


【解决方案1】:

example transaction in the documentation 在调用update 时使用await。也许您在致电set 时也需要同样的信息:

await Firestore.instance.runTransaction((transaction) async {
  var snapshot = await transaction.get(usernameDocRef);
  if (!snapshot.exists) {
    await transaction.set(usernameDocRef, {
      _UsernamesKey.userid: _user.id,
    });
  }
});

【讨论】:

  • 好建议,但我也遇到了同样的错误。
【解决方案2】:

首先,尝试使用新鲜快照中的引用和原始文档引用中的引用。如果这不起作用,请尝试将 [set] 更改为 [update],因为我记得遇到了与您现在遇到的相同的错误。

DocumentReference usernameDocRef =
        Firestore.instance.collection(_USERNAMES).document(username);

await Firestore.instance.runTransaction((transaction) async {
  var snapshot = await transaction.get(usernameDocRef);
  if (!snapshot.exists) {
    await transaction.update(snapshot.reference, {
      _UsernamesKey.userid: _user.id,
    });
  }
});

【讨论】:

    【解决方案3】:

    最近已修复此问题 - https://github.com/flutter/plugins/pull/1206

    如果您使用的是master channel,则该修复程序应该已经可用。对于其他渠道(开发版、测试版、稳定版)YMMV。

    【讨论】:

      【解决方案4】:

      我不是 Flutter/Dart 专家,但我希望您必须从事务中返回一些内容,以便 Firestore 知道您何时完成:

      await Firestore.instance.runTransaction((transaction) async {
        var snapshot = await transaction.get(usernameDocRef);
        if (!snapshot.exists) {
          return transaction.set(usernameDocRef, {
            _UsernamesKey.userid: _user.id,
          });
        }
      })
      

      【讨论】:

      • 使用这种方法我仍然会遇到同样的错误:-(
      • 对不起,这对邓肯没有帮助。在那种情况下,我不知道出了什么问题。希望别人看到的是。
      猜你喜欢
      • 1970-01-01
      • 2015-11-03
      • 1970-01-01
      • 1970-01-01
      • 2017-05-02
      • 1970-01-01
      • 2015-10-25
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多