Run transactionally and retrieve result in Future

2020-05-03 10:43发布

问题:

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

  }
}

回答1:

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.



回答2:

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.