4

Has anyone succeeded in using Squeryl's externalTransactionManagementAdapter with play framework 2.0?:

    object Global extends GlobalSettings {
      override def onStart(app: Application) {

        SessionFactory.externalTransactionManagementAdapter = Some(() => 
            Some(new Session(
                DB.getDataSource().getConnection(), 
                dbAdapter)
            )
        )
    }

I am not able to get Squeryl to return the connections to the pool. It does work with SessionFactory.concreteFactory, but then I have to use transaction blocks instead of squeryl participating in Play's transaction management.

This question is a more specific variant of my earlier question: How to integrate the Scala Squeryl ORB with play 2.0 framework?.

Community
  • 1
  • 1
Roar Skullestad
  • 2,427
  • 3
  • 26
  • 35

2 Answers2

3

This plagued me for the last two days, so I grabbed some coffee and wasted an hour of my life, but I'd like to show you how I got it working:

In your Global.scala put this:

 override def onStart(app: Application) {
    SessionFactory.externalTransactionManagementAdapter = Some(() => {
    if(org.squeryl.Session.hasCurrentSession) {
      org.squeryl.Session.currentSessionOption.get
    }
    else {
      val s = new org.squeryl.Session(DB.getDataSource().getConnection(), new PostgreSqlAdapter){
        override def cleanup = {
          super.cleanup
          unbindFromCurrentThread
        }
      }
      s.bindToCurrentThread
      s
    }
    })
  }

And then you'll need to do some clean up so your app doesn't bugger out (in same Global):

  /**
   * cleans up Squeryl thread to each request
   */
  override def onRouteRequest(request: RequestHeader): Option[Handler] = {
    org.squeryl.Session.currentSessionOption.foreach(_.unbindFromCurrentThread)
    super.onRouteRequest(request)
  }

I'll update this if I find any caveats, etc. The overriding of cleanup courtesy of http://lunajs.blogspot.ca/2011/06/squeryl-with-java-experiment.html

crockpotveggies
  • 12,682
  • 12
  • 70
  • 140
  • I might have an update for this, could be a conflict if you're using `KeyedEntity` – crockpotveggies Mar 29 '12 at 00:25
  • Ok updated the answer with some different code that is doing the trick ;) – crockpotveggies Mar 29 '12 at 00:57
  • 1
    You may want to read Max's (the squeryl author) comment in this question: http://stackoverflow.com/questions/9703688/how-to-integrate-the-scala-squeryl-orb-with-play-2-0-framework. In short he is advicing against using externalTransactionManagementAdapter with Play. – Roar Skullestad Apr 25 '12 at 09:27
  • Interesting, thanks for sharing. I did run into problems after extended usage where connections leaked again from the connection pool, so Roar's answer below may have more merit in the long-run – crockpotveggies Apr 25 '12 at 16:57
0

I am currently "cheating", using SessionFactory.concreteFactory and :

trait SquerylTransaction {
  def TransAction(f: Request[AnyContent] => Result): Action[AnyContent] = {
    Action { request =>
      transaction {
        f(request)
      }
    }
  }
}

and in the controller:

object Application extends Controller with SquerylTransaction {

  def doStuff() = TransAction { 
    //squeryl query      
  }
}

but DeLonge's solution might be better.

My Global.scala looks like this:

object Global extends GlobalSettings {

  val dbAdapter = new PostgreSqlAdapter()

  override def onStart(app: Application): Unit = {
    SessionFactory.concreteFactory = Some(() =>
      Session.create(
        DB.getDataSource().getConnection(),
        dbAdapter))
  }

}
Roar Skullestad
  • 2,427
  • 3
  • 26
  • 35
  • not sure if you're having the same problems, but the limitation i found to using `transaction {}` was that for whatever reason multiple DB connections were being opened. but if you get it working please do update :) – crockpotveggies Apr 05 '12 at 21:46