CDIでこのようなことをするのは安全ですか?
@Named
@ApplicationScoped
public class DAO {
@PersistenceContext
private EntityManager entityManager;
}
EntityManager
自体はスレッドセーフではないため、@ApplicationScoped
のような共有グローバルコンテキストでは使用しないでください。ただし、@PersistenceContext
で挿入されたオブジェクトは、実際には基になるEntityManager
のスレッド対応ラッパーであるため、これで問題ありませんか?
この件に関する他の投稿を見たことがありますが、この特定のケースに対する信頼できる答えを見つけることができませんでした。例えば:
Java CDI @PersistenceContextとスレッドセーフ
たとえば、@Stateless
と一緒に使用しても安全なようですが、それが@Stateless
の動作方法によるものなのか、それとも@PersistenceContext
自体に固有の何かによるものなのかはわかりません。
[〜#〜] edit [〜#〜]私の混乱の原因は、@PersistenceContext
がEntityManager
ラッパーを注入したことです進行中のトランザクションがすでにあるかどうかを把握するために、現在のスレッドを認識しているようです。したがって、おそらく私はスレッド認識とスレッドセーフを混同していて、それらは2つの異なるものです。
この場合、CDIはエンティティマネージャのコンテキストプロキシを作成しないと確信しています。結局のところ、それはどのような範囲にあるのでしょうか?架空の_@ThreadScoped
_または単に_@RequestScoped
_に似たものが必要な場合がありますが、_@PersistenceContext
_はCDI注釈ではなく、CDIはそのセマンティクスを変更しません。
つまり、ここで起こっているのはJava EE 6プラットフォームの「マネージドBean」インジェクションです。これは、サーブレットにエンティティマネージャをインジェクションするのと似ています。どちらの場合も、スレッドセーフではないインスタンスが提供されます。直接使用します。
たとえば、@ Statelessで使用しても安全なようですが、それが@Statelessの動作方法によるものなのか、@ PersistenceContext自体に固有の何かによるものなのかはわかりません。
これは、_@Stateless
_の動作方法によるものです。ステートレスBeanのメソッドへのすべてのリクエスト(呼び出し)は、コンテナによって一意のインスタンスにルーティングされます。コンテナは、同じBeanで2つのスレッドがアクティブにならないことを保証します。
CDIを使用すると、エンティティマネージャーをリクエストスコープのBeanにカプセル化し、それをアプリケーションスコープのBeanに注入することで、リクエストごとに同様の効果を得ることができます。
_import javax.enterprise.context.RequestScoped;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
@RequestScoped
public class EntityManagerProvider {
@PersistenceContext
private EntityManager entityManager;
public EntityManager getEntityManager() {
return entityManager;
}
}
_
以前にエンティティマネージャを注入したBeanにこれを注入します。
_@Named
@ApplicationScoped
public class DAO {
@Inject
private EntityManagerProvider entityManagerProvider;
}
_
これにより、リクエストごとに一意のエンティティマネージャーが提供されます。これもプロデューサーメソッドに簡単に変換できるため、注入されたプロバイダーでgetEntityManager()
を呼び出す必要はありません。