Run transactionally and retrieve result in Future

2020-05-03 10:24发布

How to run a transactionally statement in Slick 3.1.x, and capture the result in a Future (without the use of Await)?

This works (but uses 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)

However this does not print anything:

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

UPDATE

This is the real code taken from the program that doesn't work. It prints "1" but it never prints "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

  }
}

2条回答
Luminary・发光体
2楼-- · 2020-05-03 11:08

Coming from the other question you asked: You are opening and then immediately closing the db connection in the finally clause. Therefore your async db operation runs against a closed db connection. That's also why it works by using Await since that blocks the execution of db.close until you received the result set.

So how to fix this?

Either you move db.close into future.map or better you let play-slick handle db connections for you.

Side note

You should close your other question and update this thread accordingly instead.

查看更多
贪生不怕死
3楼-- · 2020-05-03 11:19

Your second example is fine. My guess is that you are either running it in standalone program or in test - and it simply finishes before future has a chance to be executed.

Try to add some sleep after your code in your second sample and you'll see it is getting printed. This is definitely not something (this sleep) you would do in your actual code but it will show you it works as it should.

查看更多
登录 后发表回答