Slick运行方法返回的Future会在插入行之前成功完成

时间:2019-03-26 23:04:55

标签: postgresql scala slick-3.0

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

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

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

The program flow diagram

doStuff调用foo来加载数据并将其存储在数据库中,然后返回Future。然后在doStuff中映射此Future并调用barbar栏从数据库中检索行并进行处理。但是,由于在调用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容器中运行。我在做什么错了?

我也无法摆脱一年半以前选择的用户名现在的适用性。

1 个答案:

答案 0 :(得分:2)

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

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

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