【问题标题】:Future returned by Slick run method completes successfully before rows have been inserted在插入行之前,Slick run 方法返回的 Future 成功完成
【发布时间】:2019-08-17 10:39:22
【问题描述】:

我正在使用 Slick 和 PostgreSQL 进行存储的 Scala 应用程序。我有一个方法 foo 从 CSV 文件中读取数据并将大约 10,000 行插入到数据库中。在行插入操作的 Future 完成后,另一个方法 bar 被调用,它从数据库中检索这些行并对它们执行一些操作。这就是问题所在:实际上没有从数据库中检索到任何行,因为在 Future 完成时还没有插入任何行。

从我在寻找答案和官方文档中收集到的信息来看,在插入语句成功执行之前,Future 不应该完成。如果我将以下代码Thread.sleep(30000) 添加到bar,允许首先执行插入语句,则方法提供预期的结果。现在,出于显而易见的原因,我宁愿不这样做,所以我正在寻找替代方案。

下图说明了调用初始方法doStuff后的程序流程:

doStuff 调用foo,后者加载数据并将其存储在数据库中,然后返回 Future。然后在doStuff 中映射这个Future 并调用barbar bar 从数据库中检索行并处理它们。但是,由于在调用 bar 的位置没有插入任何行,因此不会处理任何数据。

doStuff 方法:

def doStuff(csvFile: File): Future[Unit] = {
  fooService.foo(csvFile)
    .map(_ => {
      csvFile.delete()
      barService.bar()
    })
}

foo 方法:

def foo(file: File) Future[Unit] = {
  val reader = CSVReader.open(file)
  fooStorage.truncateFooData().map(_ => {
    val foos = for (line <- reader.iterator if
    line.head != "bad1" &&
      line.head !="bad2")
      yield parseFooData(line)
    fooStorage.saveFooDataBulk(foos.toSeq)
  })
}

我如何使用 Slick 插入行:

override def saveFooDataBulk(fooSeq: Seq[Foo]): Future[Seq[Foo]] =
  db.run(DBIO.seq(fooQuery ++= fooSeq)).map(_ => fooSeq)

我希望在所有行都插入数据库后立即调用bar,但是,目前来自 Slick 的 Future 完成得太快了。如果它是相关的:当请求发送到 Akka Http 端点时调用 doStuff 方法。应用程序和数据库在两个不同的 docker 容器中运行。我做错了什么?

我也无法忘记我一年半前选择的用户名现在有多合适。

【问题讨论】:

    标签: postgresql scala slick-3.0


    【解决方案1】:

    def foo 中将map 替换为flatMap。否则,它将启动一个Future[Seq[Foo]],然后立即返回一个(),然后被您的doStuff 丢弃。像这样的:

    fooStorage
      .truncateFooData()
      .flatMap(_ => {
        /* stuff... */
        fooStorage.saveFooDataBulk(foo.toSeq)
      })
      .map(_ => ())
    

    我没有测试它,但无论如何,在另一个 Future.map 中间开始一些 Futures 然后立即返回一个 () 感觉不太正确。

    【讨论】:

    • 我想我明白问题所在了。来自 truncateFooData 的 Future 完成并使用提供的 lambda 进行映射。然而,我天真地期望 doStuff 中的地图会等待 saveFooDataBulk Future,但那个 Future 是外部 Future 的结果,它会更快完成。通过使用 flatMap,内部的 Future 也必须完成。那是对的吗?我对 Scala 很陌生,所以也许有一种更简洁的方法可以实现我想要实现的目标?
    • @SlickVick 我认为您的理解基本上是正确的。也许有人可能想将与iterator 相关的代码从Future 相关的东西中移出,然后编写一个更短、更清晰的for-comprehension,它只涉及Futuremap 和@ 987654336@。我可能会稍微不同地重新排序和重新缩进整个事情,但原则不会有太大变化。
    猜你喜欢
    • 2021-05-22
    • 2017-06-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-02-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多