【问题标题】:Scala+Slick 3: Inserting the result of one query into another tableScala+Slick 3:将一个查询的结果插入另一个表
【发布时间】:2016-04-30 10:45:06
【问题描述】:

这个问题是关于 slick 3.0 或 3.1(我对此很灵活)

我有一个中间查询,我使用mapfor 等进行处理以获得我想要的结果。最后我有一个

val foo: DBIOAction[Seq[MySchema.Bar], NoStream, Effect.Read]

现在我有一个val bar: TableQuery[MySchema.Bar],我想将 foo 插入其中。

如果 foo 是 Seq,我可以简单地使用 bar ++= foo,但事实并非如此。

我发现的唯一方法是通过等待来实现结果。像这样

val query = (bar ++= Await.result(db.run(foo), Duration.Inf))

显然query 需要在某个时候与db.run 一起运行。但现在我有两个数据库运行。一次运行所有内容不是更好吗?

有更好的方法吗?

【问题讨论】:

  • bar += foo ?但是无论是+= 还是++=...(?),您仍然需要db.run
  • 我认为 ++= 有副作用的是 slick2 api,而 slick3 功能更强大,所以它需要你明确地做一个db.run
  • 是的,++= 的结果现在是一个需要运行的查询。我在这一点上编辑了问题。但我必须为此任务执行两次 db.run 调用。

标签: scala slick slick-3.0


【解决方案1】:

DBIOActionmap/flatMap 函数,所以你可以写类似的东西

val insertAction = foo.flatMap(bar ++= _)

insertAction 将是DBIOAction[Int, NoStream, Effect.Write] 或类似的类型(我不完全确定Int 和效果),然后您可以使用@987654329 在数据库上像任何DBIOAction 一样运行它@;然后你得到的是整个查询和插入结果的未来。

【讨论】:

  • flatMap 可以解决问题。最后,我只剩下一个 DBIOAction 需要运行。我在这个话题上遇到了另一件事:我应该什么时候做 db.run()?这是一个示例val foo = db.run( persons.result.map(_.map {p => tr(td(p.id)) })),我可以这样做,或者我可以在.result 之后结束db.run 部分。两种方法都给我相同的Future,在性能方面有什么区别吗?
  • 一般情况下你希望尽可能在DBIO级别工作;当你调用db.run 时,slick 将使用它自己的执行上下文运行尽可能多的查询,它会返回Future。我认为,如果你这样做,性能可能会有所不同,因为 slick 会优化线程在数据库访问方面的使用。
【解决方案2】:

问题已经得到解答,但我来这里是为了寻找不同的解决方案,所以也许这对其他人有帮助。

正如@Aldo 所说,我们希望尽可能在 DBIO 级别工作,但我会进一步说您应该尽可能在 Query 级别工作,因为这会编译为单个 sql 语句可以发送到数据库。

例如,选择中的插入应编译为INSERT INTO table1 SELECT...。如果您使用 flatMap 使用多个 DBIOS,就像建议的那样,这将被编译成 SELECT,值将被带到内存中,然后将编译 INSERT 语句,将值插入字符串中,这个新的查询将被发送到数据库。实际上,如果您的选择返回许多结果,这可能会慢得多,并且在最坏的情况下会耗尽您的内存。

因此,要将这样的内容编译成单个查询,您可以编写:

val bar: TableQuery[MySchema.Bar]

val foo: Query[MySchema.Bar, Bar, Seq]

val insert: DBIO[Int] = bar.forceInsertAll(foo)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-04-18
    • 2014-04-29
    • 2013-10-28
    • 2014-08-18
    • 2011-09-15
    • 1970-01-01
    相关资源
    最近更新 更多