- 通話漏えい接続を選択する
EntityManagerFactory emf = Persistence.createEntityManagerFactory("foo"); EntityManager em = emf.createEntityManager(); Query query = em.createQuery("select bar from Bar);
select 呼び出しで EntityManager リソースを閉じる必要がありますか? そうしないと接続がリークしますか?
EMF を使用して独自の EntityManager インスタンスを作成している場合は、それらを閉じる必要があります。
管理されたコンテナー (JBoss AS やその他の EJB コンテナーなど) 内で実行している場合は、Bean に EntityManger を注入することができ、Bean を閉じることを心配する必要はありません。
間違いなく、常に EntityManagers を閉じてください。
同様の接続リークがありました。根本的な原因は、select ステートメントが暗黙的にトランザクションを開始することでした。EntityManager.close() が呼び出されたとき、そのトランザクションはまだアクティブであり、何らかの理由で接続を開いたままにします。
さらに悪いことに、私たちの接続プールは、この状態で動かなくなった接続を回収しませんでした。
私の修正は、entityManager を閉じる前にアクティブなトランザクションを明示的にチェックすることでした。このための小さなヘルパー関数を書きました。
public static void rollbackAndClose(EntityManager mgr) {
if (mgr != null) {
EntityTransaction transaction = mgr.getTransaction();
if (transaction.isActive()) {
transaction.rollback();
}
mgr.close();
}
}
(SQLクライアントをOracleまたはSQLServerから切断するときにトランザクションが自動的にロールバックすることに慣れているため、EntityManagerの動作は直感に反します.JPAがこの動作を指示するのか、それともHibernateまたはMySQLに固有のものなのかはわかりません.)
表示されたスニペットから、アプリケーションはスタンドアロンであり、JBoss AS などの Java EE コンテナー内または Spring を使用して実行されるマネージド アプリケーションではないように見えます (議論のために Java EE コンテナーと見なすことができます)。次のWikiによると、Application-Managed Entity Manager で実行しています。そのため、エンティティ マネージャーとファクトリを明示的に閉じる必要があります。
トランザクション境界で EntityManager を閉じる必要があることを明確にしたいと思います。hibernate Session のコードを見ると (EntityManagerImpl.close() 実際にセッションを閉じるデリゲート)。トランザクションを閉じ、永続化コンテキストをクリアすることに気付くでしょう。EntityManagerFactory を閉じることは、よりアプリケーション レベルであるため、再利用して、アプリケーションを破棄するときに閉じることができます。
そうは言っても、接続リークに関する懸念に従って、接続は休止状態によって直接管理されないことに注意してください。Hibernate には、接続プールとの統合を可能にするプラグイン アーキテクチャがあります。Hibernate (バージョン 3.3 以降だと思いますが、確かではありません) には、本番環境には推奨されないデフォルトの接続プーリング メカニズムが付属しています。デフォルトのものを使用している場合、接続リークの原因である可能性があります (次の投稿を参照してください)。
休止状態で使用される最も一般的な接続プールは C3P0 です (これが最適かどうかはわかりません..)。管理されていない環境では、接続プールの構成を確認する必要があります (例: hibernate.c3p0.* 関連の hibernates プロパティ)。