【问题标题】:Run transactionally and retrieve result in Future以事务方式运行并在 Future 中检索结果
【发布时间】:2016-12-02 18:38:41
【问题描述】:

如何在 Slick 3.1.x 中运行 transactionally 语句,并在 Future 中捕获结果(不使用 Await)?

这有效(但使用等待)

 val action = db.run((for {
      _ <- table1.filter(_.id1 === id).delete
      _ <- table2.filter(_.id2=== id).delete
    } yield ()).transactionally)
    val result = Await.result(action, Duration.Inf)

但是这不会打印任何东西:

val future = db.run((for {
      _ <- table1.filter(_.id1 === id).delete
      _ <- table2.filter(_.id2=== id).delete
    } yield ()).transactionally)
 future.map { result => println("result:"+result) }

更新

这是从不起作用的程序中提取的真实代码。它打印“1”,但从不打印“2”

case class UserRole (sk: Int, name: String)

class UserRoleDB(tag: Tag) extends Table[UserRole](tag, "user_roles") {
  def sk = column[Int]("sk", O.PrimaryKey)
  def name = column[String]("name")
  def * = (sk, name) <>  ((UserRole.apply _).tupled, UserRole.unapply)
}

class Test extends Controller  {

  def index = Action.async { request =>

    val db = Database.forConfig("db1")
    val userRoles = TableQuery[UserRoleDB]
    val ur = UserRole(1002,"aaa")

    try {

          val action = (for {
                  userRole2 <- userRoles += ur
              } yield (userRole2)).transactionally

          val future = db.run(action)
          println(1)
//        val result = Await.result(future, Duration.Inf)
          future.map { result => {
             println(2)
             Ok("Finished OK")
           }
          }
      } 
      finally db.close

  }
}

【问题讨论】:

  • 你的代码没问题。也许应用程序在未来完成之前退出。尝试在映射未来后添加一些 Thread.sleep 以查看它是否有效。
  • 对于像println这样的副作用函数(返回Unit),最好使用foreach(而不是map)。
  • 如果future.map 没有生效是因为未来可能会失败,请尝试附加.recover.recoverWith

标签: scala slick slick-3.0


【解决方案1】:

来自other question you asked:您在finally 子句中打开然后立即关闭数据库连接。因此,您的异步数据库操作针对已关闭的数据库连接运行。这也是它使用Await 起作用的原因,因为这会阻止db.close 的执行,直到您收到结果集。

那么如何解决这个问题?

要么将db.close 移动到future.map,要么让play-slick 为您处理数据库连接。

旁注

您应该关闭您的other question 并相应地更新此线程。

【讨论】:

    【解决方案2】:

    你的第二个例子很好。我的猜测是,您要么在独立程序中运行它,要么在测试中运行它——它只是在未来有机会执行之前完成。

    尝试在您的第二个示例中添加一些睡眠之后,您会看到它正在打印。这绝对不是你在实际代码中会做的事情(这个睡眠),但它会告诉你它应该按原样工作。

    【讨论】:

    • 我在 Play 2.5 中运行它,而不是独立运行。由于某种原因,future.map 未执行
    • 你能粘贴更大的代码吗?就像它如何与 Play 中的控制器处理交互一样?
    • 正如@PNeyens 建议的那样尝试添加恢复(虽然你说它适用于Await.result(),所以它不应该是问题,但让我们确定......)。除此之外 - 这段代码是:``` future.map { result => { println(2) UpdateOk(result.sk) } } ``` 你的控制器返回了什么?
    • Please see this question,我做了一个独立的代码来复制问题
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-12-30
    • 1970-01-01
    • 2020-02-27
    • 1970-01-01
    • 1970-01-01
    • 2021-02-18
    相关资源
    最近更新 更多