1

Hibernate、c3p0、Guice、Guice-persistを使用すると、トランザクション後にデータへの接続がプールに解放されないという奇妙な問題が発生します。

これは、 JpaPersistServiceが実行される方法に関連しているようで、EntityManagerをthreadLocal変数にキャッシュします。

private final ThreadLocal<EntityManager> entityManager = new ThreadLocal<EntityManager>();

私の質問は次のとおりです。

  • guice-persistを削除し、これを新しいentityManagerを作成するものに置き換えて、必要なたびに閉じる必要がありますか(ここで提案されています)?
  • または、entityManagerをキャッシュするのが方法であり、他の何かで問題を修正する必要がありますか?

(私たちの問題:1)従来の8時間のタイムアウト後にmysqldによってmysql接続が切断されたため、entityManagerは使用できなくなりました。c3p0のキープアライブを有効にすることで解決できますが、アプリケーションが長期間使用されない場合があるため、無駄なアクティブな接続を維持しないようにします。2)各EntityManagerは何らかのキャッシュを実行しているようであり、エンティティはentityManager間で一貫性がありません。それを解決する方法を見ていませんでした)

4

2 に答える 2

3

ついに解決策を見つけました。

guice-persistの特定のバグのようです。

EntityManagerがトランザクションの外部に挿入された場合、UnitOfWorkまたはトランザクションの外に挿入された場合、決して閉じないEntityManagerが作成され、奇妙な問題が発生します。

guice-persistのドキュメントはこれを指摘していません。

解決策は、トランザクション内にいない場合、またはトランザクション内にいない場合はProvider<EntityManager>、直接ではなく常に注入することです。EntityManagerUnitOfWork

于 2013-02-02T10:45:24.640 に答える
2

私が経験したのと同じ問題があると思います: Guice JPA - 「この接続は閉じられました。」エラー

問題 730ですべてうまく説明されています: 自動的に開始された UnitOfWork は決して終了しません

JpaPersistService を使用しているときに、アクティブな UnitOfWork の外部にある EntityManager にアクセスしようとすると、Guice が自動的に 1 つを開始します。ただし、Guice はこの UnitOfWork をいつ終了するかを認識していない (そして認識できない) ため、決して認識しません。

結果?問題のあるスレッドは、アプリケーションの存続期間中、同じ EntityManager でスタックします。これはアプリケーションが実行するのに悪い状態であり、私たちのものはしばらくすると使用可能なメモリを使い果たし、クラッシュすることは避けられません。

ここでの本当の致命的な点は、いつこの間違いを犯したかがまったくわからないことです。唯一の本当のヒントは、(EM の第 1 レベルのキャッシュが原因で) 異なるスレッド間でデータベースから一貫性のないデータを取得していること、またはアプリケーションのメモリ消費量が増え続けていることです。私の場合、それを疑うようになったのはプール内のアクティブな接続でした。その後、詳細なログをオンにすると、アプリがプールから接続をまったく借りていないことに気付きました。代わりに、すでに保持されている接続を再利用していました。クローズされていない EntityManager。

実際には、この問題のかなりの重複が報告されています: http://code.google.com/p/google-guice/issues/list?can=1&q=UnitOfWork

したがって、EntityManager を注入してもあまり効果がないと思います。EntityManager メソッドを実際に使用すると、問題が発生します。すべてのアクセスが UnitOfWork 内にあることを確認する必要があります。それを行う方法は、アプリケーションによって異なります。

于 2013-02-15T16:06:58.523 に答える