简体   繁体   English

在 Flutter 的 Firebase Firestore 中的事务中保存数据的问题

[英]Problem with saving data in Transaction in Firebase Firestore for Flutter

I have a problem with transactions in my web application created in Flutter.我在 Flutter 中创建的 web 应用程序中的事务存在问题。 For database I use Firebase Firestore where I save documents via transaction.对于数据库,我使用 Firebase Firestore,我通过事务保存文档。

Dependency:依赖:
cloud_firestore: 3.1.1 cloud_firestore:3.1.1

StudentGroup is my main document. StudentGroup 是我的主要文档。 It has 4 stages and each of them has 3-5 tasks.它有 4 个阶段,每个阶段有 3-5 个任务。 (Everything is in 1 document). (所有内容都在 1 个文档中)。 I have to store game timer, so every 10 seconds I make an request to save time for current stage.我必须存储游戏计时器,所以每 10 秒我都会请求为当前阶段节省时间。 (Every stage has different timer). (每个阶段都有不同的计时器)。 I have a problem with saving task, because "Sometimes" when 2 requests are made in the same time, then I get some weird state manipulation.我在保存任务时遇到问题,因为“有时”当同时发出 2 个请求时,我会得到一些奇怪的 state 操作。

  1. Task is updated and "isFinished" is set to true任务已更新,“isFinished”设置为 true
  2. Timer is updated to correct value (with this update somehow previous task update is lost, "isFinished" is set to false计时器更新为正确值(此更新以某种方式丢失了先前的任务更新,“isFinished”设置为 false

This is how I save task.这就是我保存任务的方式。

Future<Result> saveTask({required String sessionId, required String studentGroupId,
  required Task task}) async {
  print("trying to save task <$task>.");
  try {
    return await _firebaseFirestore.runTransaction((transaction) async {
      final studentGroupRef = _getStudentGroupDocumentReference(
          sessionId: sessionId,
          studentGroupId: studentGroupId
      );
      final sessionGroupDoc = await studentGroupRef.get();

      if (!sessionGroupDoc.exists) {
        return Result.error("student group not exists");
      }

      final sessionGroup = StudentGroup.fromSnapshot(sessionGroupDoc);
      sessionGroup.game.saveTask(task);
      transaction.set(studentGroupRef, sessionGroup.toJson());
    })
    .then((value) => taskFunction(true))
    .catchError((error) => taskFunction(false));
  } catch (error) {
    return Result.error("Error couldn't save task");
  }
}

This is how I save my time这就是我节省时间的方法

Future<Result> updateTaskTimer({required String sessionId,
  required String studentGroupId, required Duration duration}) async {
  print("trying to update first task timer");
  try {
    return await _firebaseFirestore.runTransaction((transaction) async {
      final studentGroupRef = _getStudentGroupDocumentReference(
          sessionId: sessionId,
          studentGroupId: studentGroupId
      );
      final sessionGroupDoc = await studentGroupRef.get();

      if (!sessionGroupDoc.exists) {
        return Result.error("student group not exists");
      }

      final sessionGroup = StudentGroup.fromSnapshot(sessionGroupDoc);
      switch (sessionGroup.game.gameStage) {
        case GameStage.First:
          sessionGroup.game.stages.first.duration = duration.inSeconds;
          break;
        case GameStage.Second:
          sessionGroup.game.stages[1].duration = duration.inSeconds;
          break;
        case GameStage.Third:
          sessionGroup.game.stages[2].duration = duration.inSeconds;
          break;
        case GameStage.Fourth:
          sessionGroup.game.stages[3].duration = duration.inSeconds;
          break;
        case GameStage.Fifth:
          sessionGroup.game.stages[4].duration = duration.inSeconds;
          break;
      }
      transaction.set(
          studentGroupRef,
          sessionGroup.toJson(),
          SetOptions(merge: true)
      );

      print("Did I finish task 4? ${sessionGroup.game.stages.first.tasks[3].isFinished}");

    })
    .then((value) => timerFunction(true))
    .catchError((error) => timerFunction(false));
  } catch (error) {
    return Result.error("Error couldn't update task timer");
  }
}

timerFunction and taskFunction print some messages in console and return Result.error or Result.success (for now it returns bool) timerFunction 和 taskFunction 在控制台打印一些消息并返回 Result.error 或 Result.success(现在它返回 bool)

I don't know If I am doing something wrong with Firebase Firestore Transaction.我不知道我是否对 Firebase Firestore 事务做错了什么。 I would like to have atomic operations for reading and writing data.我想有原子操作来读写数据。

Transactions ensure atomicity - which means that if the transaction succeeds then all the reads and writes occur in a non-overlapping way with other transactions.事务确保原子性 - 这意味着如果事务成功,则所有读取和写入都以与其他事务不重叠的方式发生。 This prevents the type of problem you are describing.这可以防止您描述的问题类型。

But this doesn't work if you spread your reads and writes over multiple transactions.但是,如果您将读写分散到多个事务上,这将不起作用。 In particular, it looks to me like you are writing a task which was obtained from outside the transaction.特别是,在我看来,您正在编写一个从事务外部获得的任务。 Instead, you should use ids or similar to track which documents you need to update, then do a read and a write inside the transaction.Alternatively firebase also provides Batched Writes , which specify the specific properties you want to update.相反,您应该使用 ids 或类似的方法来跟踪您需要更新的文档,然后在事务中执行读取和写入操作。或者 firebase 还提供批量写入,它指定您要更新的特定属性。 These will ensure that any other properties are not changed.For batch writes example you can refer to the link这些将确保不会更改任何其他属性。对于批量写入示例,您可以参考链接

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

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