webappは、SpringのOpenSessionInViewInterceptor
を使用して、リクエストごとにHibernateセッションを開き、リクエスト処理の終了時に閉じる。これは非常にうまくいく。しかし、ファイルのダウンロードのような要求の中には、セッションを開いたままにしてDB接続を張っておく時間が長くかかることがあります。私たちの場合、ファイルデータをレスポンス出力ストリームにコピーすることは、コントローラが行う最後の処理であり、Hibernateセッションは必要ありません(ファイルデータはサーバファイルシステムから読み込まれます)。これらのファイルのダウンロード要求は、db接続プール内のほとんどの接続を迅速に消費する可能性があります。OpenSessionInViewInterceptorを使用するとセッションを終了する(&db接続をプールに戻す)方法
私はコントローラにSessionFactory
への参照を与えられた、とだけ応答出力ストリームにファイルデータをコピーする前に、次のメソッドを呼び出しました:
SessionFactoryUtils.closeSession(SessionFactoryUtils.getSession(sessionFactory, false));
OpenSessionInViewInterceptor
は後で要求プロセスで同じことを行いセッションを閉じることは冪等であるように見えます(つまり、このメソッドを複数回呼び出すと、1回呼び出すのと同じ効果があります)。言い換えれば、この変更のローカルテストは順調でした。しかし、それはちょっと危険なようです。 Springのそれ以降のバージョンでOpenSessionInViewInterceptor
またはSessionFactoryUtils
が変更された場合、このアプローチは微妙な方法で壊れている可能性があります(接続が漏れている可能性があります)。
最終的な目標は、ファイルデータの送信を開始する前にデータベース接続を閉じることです。これはその達成方法の1つです。もう1つの解決策は、コントローラが入力ストリームを属性として要求に入れ、フィルタを(OpenSessionInViewInterceptor
の後に起動する)入力ストリームのデータを応答にコピーすることです。これには独自の課題があります(たとえば、コントローラに集中する代わりに、コントローラとフィルタの間で関連するコードが分割されるなど)。
これを処理するより良い方法はありますか?
これはこれまでのやり方です。ファイルのダウンロード操作にOSiVを使用しないでください。 –
提案していただきありがとうございます。私はそのオプションを検討しましたが、アプリケーション内の別のパスからのファイルダウンロードがいくつかあります。 OSiVは現在すべての要求に適用されています。分散したファイルのダウンロードパスにより、OSiVを選択的にオプトアウトすることが困難になります。おそらく、すべてのファイルのダウンロードを共通のパスに移動する必要があります。そのため、これらの要求にOSiVを適用しない方が簡単でしょう。 –