【问题标题】:How to run multiple plain sql queries in a single transaction in slick?如何在 slick 的单个事务中运行多个普通 sql 查询?
【发布时间】:2016-12-04 05:08:28
【问题描述】:

我有一个 Play/Slick 应用程序,我需要在单个事务中运行多个普通 sql 查询,检索最后一个查询的结果,如下所示:

val id: Future[Int] = db.run {
    sql"""
        DECLARE @T TABLE (id INTEGER)
        INSERT INTO Foo (name) OUTPUT INSERTED.id INTO @T VALUES ('bar')
        SELECT id FROM @T
    """.as[Int].head
}

上面的问题是它总是返回1,这是声明临时表的顶级查询的结果。我如何获得最后一个查询的结果?有问题的数据库是 MS SQL Server。玩 2.5.4,Slick 3.1.1。

【问题讨论】:

  • 将它们拆分为单独的操作并进行理解?然后添加.transactionally?
  • @insan-e 我正在尝试类似的方法,但无法弄清楚语法,根本没有示例。
  • 是的,文档说了差不多 2 句话关于查询组合...

标签: sql-server scala jdbc playframework slick


【解决方案1】:

Slick Actions 最重要的特性之一是它们是可组合的,类似于 Scala Futures。恕我直言,文档没有尽可能多地对待它......这是一个例子:

val createAction = sqlu"""DECLARE @T TABLE (id INTEGER)"""
val insertAction = sqlu"""INSERT INTO Foo (name) OUTPUT INSERTED.id INTO @T VALUES ('bar')"""
val selectAction = sql"""SELECT id FROM @T""".as[Int].head

val composedAction = for {
  createRes <- createAction
  insertRes <- insertAction
  selectRes <- selectAction
} yield selectRes

val id = db.run(composedAction.transactionally) // Future[...]

如果你觉得更容易的话,你可以用flatMaps 和最后的map 替换for 理解。

还有两个来自 Slick 的方便助手,即DBIO.seq(按顺序运行查询并丢弃结果,返回Unit)和DBIO.sequence(相同但保留 所有个人行动的结果)。

【讨论】:

  • 谢谢,我正在尝试类似的东西,但它不喜欢 selectAction 用于组合,所以您的示例无法编译并出现错误 Compilation error[value map is not a member of slick.jdbc.SQLActionBuilder]
  • 对不起,我错过了第三个查询末尾的as[Int].head,但现在错误不同了-SQLServerException: Must declare the table variable "@T".,显然意味着查询是并行执行的,所以for构造不会在这里工作,只有 flatMap 可能。
  • 我认为不是,for 理解只是 flatMap 和 map 的语法糖。可能问题在于 Slick 如何处理临时表创建和执行查询……我不是这里的专家,哈哈……xD
  • This post 说这根本不可能……
  • 我不太确定,因为我上面的示例有效,这意味着它创建临时表和所有内容都没有任何错误,仅检索最后一个查询的值不起作用,而 forflatMap 方法我很确定这些查询是并行运行的,因此会出现 sql 错误。
【解决方案2】:

如何使用 DBIO.seq()。由于 DBIO.seq 返回 Unit,因此 selectAction 紧随其后的是 andThen()。

val createAction = sqlu"""DECLARE @T TABLE (id INTEGER)"""
val insertAction = sqlu"""INSERT INTO Foo (name) OUTPUT INSERTED.id INTO @T VALUES ('bar')"""
val selectAction = sql"""SELECT id FROM @T""".as[Int].head

val id = db.run(DBIO.seq(createAction, insertAction) andThen selectAction)

【讨论】:

    【解决方案3】:

    要扩展现有答案,提供的查询可以通过省略 INTO clause 作为单个查询运行。而是:

    DECLARE @T TABLE (id INTEGER)
    INSERT INTO Foo (name) OUTPUT INSERTED.id INTO @T VALUES ('bar')
    SELECT id FROM @T
    

    可以使用以下内容:

    INSERT INTO Foo (name) OUTPUT INSERTED.id VALUES ('bar')
    

    db<>fiddle demo

    【讨论】:

      猜你喜欢
      • 2018-03-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-04-12
      • 1970-01-01
      • 2014-11-02
      • 1970-01-01
      • 2015-12-27
      相关资源
      最近更新 更多