ps0604
ps0604

Reputation: 1071

Disconnect from Slick JNDI connection in Play for Scala

Slick defines here how to connect to a database using JNDI:

val db = Database.forName(jndiName: String)

I use the above to connect to a database in Play for Scala, defining the JNDI connection in application.conf:

   def read (jndi: String, code: Int) = {
      val db = Database.forName(jndi)
      val records = TableQuery[TableDB]
      val action = records.filter(_.code === code).result
      val future = db.run(action.asTry)
      future.map{ 
        case Success(s) => 
          if (s.length>0)
            Some(s(0))
          else
            None
        case Failure(e) => throw new Exception ("Failure in read: " + e.getMessage)
      }
   }

Question is: how to disconnect from the JNDI resource? Simply db.close() ? Is there a way to implicitly close the connection when the read method ends?

Upvotes: 0

Views: 234

Answers (2)

Sam Upra
Sam Upra

Reputation: 737

You can always use play's shutdown hooks to close the db connection when you app shuts down (which is usually what you would want) and yes db.close is enough to stop the connection, your port will be freed which is all you should care about. I'm not quite sure why you would want the db to close right after the method, but there's a very easy fix to this without polluting the code, you simply inject your database into the method :

def read(db : Database, code: Int) = {
    val records = TableQuery[TableDB]
    val action = records.filter(_.code === code).result
    val future = db.run(action.asTry)
    future.map {
      case Success(s) =>
        if (s.length > 0)
          Some(s(0))
        else
          None
      case Failure(e) => throw new Exception("Failure in read: " + e.getMessage)

  } 

And the caller of this method can close the respective database once you have the results you want. Much safer and easier to change :) On the other hand, you can always go with @SergGr's solution, it also works :)

Upvotes: 1

SergGr
SergGr

Reputation: 23788

It is not clear what make you doubt it. If you look at the source of forName, you may see that it just asks JNDI context to get object by the name you provided and then treat it as javax.sql.DataSource that can create connections. DataSource is not Closeable or anything like this so you don't have to explicitly release it. It is enough to just close the db.

As for closing when the read method ends, this is probably not what you really want because you return Future that might still be not finished and thus might need the connection to be open. So what you probably need is Future.onComplete

  def read(jndi: String, code: Int) = {
    val records = TableQuery[TableDB]
    val action = records.filter(_.code === code).result
    val db = Database.forName(jndi)
    val future = db.run(action.asTry)
    future.onComplete(_ => db.close()) // <-- added line
    future.map {
      case Success(s) =>
        if (s.length > 0)
          Some(s(0))
        else
          None
      case Failure(e) => throw new Exception("Failure in read: " + e.getMessage)
    }
  }

Upvotes: 1

Related Questions