Java DAO で synchronized を使用すると問題が発生しますか?
-
12-09-2019 - |
質問
Java DAO のメソッドで 'synchronized' キーワードを使用すると、Web アプリケーションで使用するときに問題が発生しますか?
ここで見られるように、リソースの競合を避けるためにメソッドを同期する必要があるマルチスレッドのスタンドアロン アプリケーションがあるため、質問しました。
java.util.concurrent.ExecutionException: javax.persistence.PersistenceException: org.hibernate.HibernateException: Found shared references to a collection: com.replaced.orm.jpa.Entity.stuffCollection
私が懸念しているのは、多数の人がそのアプリケーションを使用しようとすると、同期されたメソッドがブロックし、アプリケーション全体の速度が低下することです。
私は Spring で注入された JPA エンティティ マネージャー ファクトリを使用しています。これは、DAO にエンティティ マネージャーを提供します。技術的には DAO 層を削除して、クラスにエンティティ マネージャー ファクトリを直接呼び出すこともできますが、私は DAO が提供する分離を楽しんでいます。
また、接続されたエンティティ ORM オブジェクトをスレッド間で受け渡さないように細心の注意を払っていることにも注意してください。DAOへのアクセス時にリソース競合エラーが発生しているのではないかと推測しています。複数のスレッドが同時に実行され、非アトミックな方法でデータベースを永続化または読み取りしようとしていると思います。
この場合、DAO を使用すると、役立つどころか害が大きくなりますか?
私が質問から外した重要な情報は、DAO がシングルトンではないということです。もし私がその詳細を含めるほど明晰に考えていたなら、おそらく最初から質問しなかっただろう。
私の理解が正しければ、Spring は DAO クラスを使用するクラスごとに、DAO クラスの新しいインスタンスを作成します。したがって、バッキング エンティティ マネージャーは各スレッドに固有である必要があります。Rob H が答えたように、エンティティ マネージャーを共有しないことがここで重要です。
ただし、同期を削除するとエラーが発生する理由がわかりません。
これによれば 糸, 、 @PersistenceContext アノテーションはスレッドセーフな SharedEntityManager を作成します。したがって、シングルトン DAO を作成できるはずです。
解決
あなたがスレッド間でエンティティオブジェクトを共有していないと言います。それは良い。しかし、あなたはまた、あなたがいずれかのスレッド間でののEntityManager のオブジェクト(または休止中のセッションのオブジェクト)を共有していないことを確認しなければなりません。春のようなフレームワークは、スレッドローカル変数にセッションを保存することにより、自動的にあなたのためにこれを管理します。あなたは、フレームワークの助けを借りずに、独自のDAOをコーディングしている場合は、それらを共有避けるための予防措置を自分で取る必要があります。
一度これを行う対話状態のどれもが、スレッド間で共有されませんので、、DAOのメソッドを同期化する理由はありません。これは非常に同時Webアプリケーションにとって重要です。代替は、1つのスレッドだけそれらはすべて同じDAOのインスタンスを共有すると仮定すると、一度にDAOにアクセスできるようになることです。スループットのためのすべてが得意ではない。
他のヒント
スレッドセーフのために同期する必要がある場合は、そのままにしておきます。その場合はとにかくブロックする必要があります。Web アプリケーションのケースでブロックが必要ない場合は、次のいずれかを行うことができます。
- ロックに競合がないときにパフォーマンスがヒットするため、データベースにヒットする費用を考慮した場合は、パフォーマンスが無視でき、取るに足らないままにしておきます。
- それを再設計して、基礎となる非色素化されたDAOを保護するスタンドアロンアプリケーションケースに同期レイヤーを追加します。
個人的には、そのままにして、プロファイリングして、リファクタリングが必要かどうかを確認します。それまでは、単に時期尚早な最適化を行っているだけです。