4

セッションとリクエストの両方を取る関数を使用する play の Action の周りに次のラッパーを書きました。最初のバージョンは次のとおりです。

def ActionWithSession[A](bp: BodyParser[A])(f: Session => Request[A] => Result): Action[A] =
  Action(bp) {
    db.withSession { 
      session: DbSession =>
        request => f(session)(request)
    }
  }

このバージョンはうまく機能します (正しい Result がブラウザに返されます) が、呼び出しごとにデータベース接続がリークします。何度か電話した後、次の例外が発生し始めました。

java.sql.SQLException: Timed out waiting for a free available connection.

以下のバージョンに変更すると(request =>アクションの直後に移動することで、接続漏れがなくなり、動作します。

def ActionWithSession[A](bp: BodyParser[A])(f: Session => Request[A] => Result): Action[A] =
  Action(bp) { request =>
    db.withSession { 
      session: DbSession =>
        f(session)(request)
    }
  }

最初のバージョンで接続がリークするのはなぜですか? また、2 番目のバージョンではそれがどのように修正されるのでしょうか?

4

2 に答える 2

3

db.withSession は、最初の引数でセッションを取得する関数を受け取り、それが提供するいくつかのセッションでそれを実行します。db.withSession の戻り値は、その関数が返すものです。

最初のバージョンでは、 withSession に渡された式は function に評価されるため request => f(session)(request)、 db.withSession は終了します: セッションをインスタンス化し、そのセッションにバインドされた関数オブジェクトをインスタンス化し、セッションを閉じます (インスタンス化された関数が呼び出される前に) !)、このバインドされた関数を返します。今、Actionまさに望んでいたものを手に入れました - を取り、Request[A]を与える関数ですResult。ただし、Play がこの Action を実行しようとすると、セッションは遅延して開かれますが、パックをプールに戻すものは何もありません。

2 番目のバージョンでは、 を呼び出すf関数を返すのではなく、実際に を呼び出している db.withSession 内で正しく実行されますf。これにより、への呼び出しがfdb.withSession 内にネストされ、セッションの取得中に発生することが保証されます。

これが誰かを助けることを願っています!

于 2013-08-22T05:12:00.200 に答える