私が使用している:MySQL、Tomcat 6、JDBC接続プーリングを備えたHibernate 3.6.8
Hibernate が多数の接続を開いているという問題に遭遇しました。これにより、最終的に Web アプリが新しい接続を取得できなくなります。最初は、接続プールなしで実行していることが問題だと思ったので、Tomcat JDBC プーリングを接続しました。
これが問題を悪化させました。いくつかのクエリの後で失敗するのではなく、すぐに失敗しました。これは、Hibernate がプール サイズ (30) よりも多くの接続を開こうとしたためであることが判明しました。確認したところ、EntityManager を作成しているすべての場所で、try がある場合は final 句内で close() を呼び出しているため、なぜそれらが開いたままになっているのかわかりませんでした。
close() のソースを見ると、トランザクションが開いていると実際には閉じないことがわかったので、エンティティ マネージャーで getTransaction().commit() を呼び出してみました。これは効果がありませんでした。次に、この構成フラグを発見し、オンにしました。
<property name="hibernate.ejb.discard_pc_on_close" value="true" />
これにより違いが生じました。出力用にオブジェクトをレンダリングしようとしたときに例外が発生しました: ロールのコレクションを遅延初期化できませんでした: XXX.Comment.attachments、セッションまたはセッションが閉じられませんでした
問題は、コメントのコレクションを作成するために多くのクエリを作成し、これらすべてのクエリで接続を開いたままにしておくことです。Comment クラスには次のものが含まれます。
@OneToMany
@JoinTable(name = "Object", joinColumns = { @JoinColumn(name = "parentId") }, inverseJoinColumns = { @JoinColumn(name = "id") })
public List<Attachment> getAttachments()
{
if (attachments == null)
{
attachments = new ArrayList<Attachment>();
}
return attachments;
}
ここでいくつかの継承が行われていることに言及します。
Attachment は KObject (データベース内のテーブル名 Object) のサブクラスであり、KObject には Comment (KObject のサブクラスでもある) にマップするために使用される parentId が含まれています。
明確にするために、エンティティマネージャーへの私の呼び出しは次のとおりです。
public <T> T findById(Class<T> objClass, String id)
{
EntityManager em = theEMF.createEntityManager();
em.getTransaction().begin();
try {
T obj = em.find(objClass, id);
return obj;
} catch(NoResultException e) {
return null;
} finally {
em.getTransaction().commit();
em.clear();
em.close();
}
}
theEMF は、最初の使用時に初期化される静的メンバー変数です。
解決策は @OneToMany(fetch=FetchType.EAGER) にすることだと思っていましたが、効果はありませんでした。私は何を間違っていますか?