如何在Play 2.0中使用Squeryl的externalTransactionManagementAdapter?

4

有人成功地在Play Framework 2.0中使用Squeryl的externalTransactionManagementAdapter吗?

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

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

我无法让Squeryl返回到连接池中。它确实可以使用SessionFactory.concreteFactory,但这意味着我必须使用事务块,而不是squeryl参与Play的事务管理。
这个问题是我先前问题的更具体变体:如何将Scala Squeryl ORB与play 2.0框架集成?
2个回答

3
这让我苦恼了两天,所以我喝了杯咖啡浪费了一小时的生命,但是我很想向您展示我是如何使它工作的:
在您的 Global.scala 中添加以下内容:
 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
    }
    })
  }

然后你需要进行一些清理,以避免你的应用程序出现问题 (在同一个全局变量中):

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

如果我发现任何注意事项等,我会及时更新。感谢http://lunajs.blogspot.ca/2011/06/squeryl-with-java-experiment.html的技术支持,使清理工作得到有效重写。


我可能有一个更新,如果你正在使用 KeyedEntity,可能会产生冲突。 - crockpotveggies
好的,我更新了答案并提供了一些不同的代码来解决问题 ;) - crockpotveggies
1
您可能想阅读Max(squeryl的作者)在此问题中的评论:https://dev59.com/6Gkw5IYBdhLWcg3ws8z3。简而言之,他建议不要在Play中使用externalTransactionManagementAdapter。 - Roar Skullestad
有趣,谢谢分享。在长时间使用后,我遇到了连接再次从连接池泄漏的问题,因此Roar在下面的回答可能在长期内更有价值。 - crockpotveggies

0

我目前在“作弊”,使用SessionFactory.concreteFactory和:

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

并在控制器中:

object Application extends Controller with SquerylTransaction {

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

但是DeLonge的解决方案可能更好。

我的Global.scala看起来像这样:

object Global extends GlobalSettings {

  val dbAdapter = new PostgreSqlAdapter()

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

}

不确定您是否遇到了同样的问题,但我发现使用 transaction {} 的限制是由于某种原因打开了多个数据库连接。但如果您成功了,请务必更新 :) - crockpotveggies

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接