2

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

私が懸念しているのは、かなりの数の人がアプリケーションを使用しようとすると、同期されたメソッドがブロックされ、アプリケーション全体が遅くなることです。

DAO にエンティティ マネージャーを提供する、Spring が注入された JPA エンティティ マネージャー ファクトリを使用しています。技術的には、DAO レイヤーを削除して、クラスにエンティティ マネージャー ファクトリを直接呼び出させることもできますが、DAO が提供する分離を楽しんでいます。

また、接続されたエンティティ ORM オブジェクトをスレッド間で受け渡さないように細心の注意を払っていることにも注意してください。DAOへのアクセス時にリソース競合エラーが発生するのではないかと推測しています。複数のスレッドが同時に進行していて、非アトミックな方法でデータベースを永続化または読み取りしようとしていると思います。

この場合、DAO を使用すると、助けよりも害が大きくなりますか?


私が質問から外した重要な情報は、DAO がシングルトンではないということです。その詳細を含めるのに十分明快に考えていたなら、そもそもその質問をしなかったでしょう.

私の理解が正しければ、Spring はそれを使用するクラスごとに DAO クラスの新しいインスタンスを作成します。したがって、バッキング エンティティ マネージャーは各スレッドに固有である必要があります。Rob H が答えたように、ここで重要なことは、エンティティ マネージャーを共有しないことです。

ただし、同期を削除するとエラーが発生する理由がわかりません。


このスレッドによると、 @PersistenceContext アノテーションはスレッドセーフな SharedEntityManager を作成します。したがって、シングルトン DAO を作成できるはずです。

4

2 に答える 2

3

スレッド間でエンティティオブジェクトを共有していないと言います。それは良い。ただし、 EntityManagerオブジェクト(またはHibernateのSessionオブジェクト)をスレッド間で共有していないことも確認する必要があります。Springのようなフレームワークは、セッションをスレッドローカル変数に格納することでこれを自動的に管理します。フレームワークの助けを借りずに独自のDAOをコーディングしている場合は、それらを共有しないように自分で予防策を講じる必要があります。

これを行うと、会話状態はスレッド間で共有されないため、DAOメソッドを同期する理由はありません。これは、並行性の高いWebアプリケーションにとって重要です。別の方法は、すべてが同じDAOインスタンスを共有していると仮定すると、一度に1つのスレッドのみがDAOにアクセスできるようにすることです。スループットにはまったく良くありません。

于 2009-07-10T17:34:15.413 に答える
1

スレッドセーフのために同期する必要がある場合は、そのままにしておきます。その場合はとにかくブロッキングが必要です。Web アプリケーションのケースでブロックが必要ない場合は、次のいずれかを実行できます。

  • ロックに競合がない場合のパフォーマンスへの影響は無視できるほどであり、データベースへのアクセスのコストを考慮すると取るに足らないものであるため、そのままにしておきます。
  • 基になる非同期 DAO を保護するスタンドアロン アプリケーション ケースの同期レイヤーを追加するように再設計します。

個人的には、そのままにしてプロファイルを作成し、リファクタリングが必要かどうかを確認します。それまでは、時期尚早の最適化を行っているだけです。

于 2009-07-10T16:18:50.573 に答える