web-dev-qa-db-ja.com

JAVA:マルチスレッド環境のEntityManagerオブジェクト

複数のスレッドがある場合、それぞれがインジェクターを使用してEntityManagerオブジェクトを取得し、それぞれがemオブジェクトを使用して他のクラスオブジェクトのリストを選択します。 forループで使用する準備ができました。

スレッドが最初に終了してclear()を呼び出すと、他のスレッドに影響しますか? forループのように例外がありますか?

Close()はどうですか?

答えが「依存する」である場合、どのようにして(クラス定義?メソッド呼び出し?)どこ(Javaコード?アノテーション?xml?)を調べて、どのように依存しているかを確認する必要がありますか?

私はソースを書きませんでした、私はドキュメントなしで誰か他の人のライブラリを使っています。

ありがとうございました。

22
user1589188

ここでは完全に動作していますthread-safe Entity Manager Helper

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;

public class EntityManagerHelper {

    private static final EntityManagerFactory emf;
    private static final ThreadLocal<EntityManager> threadLocal;

    static {
        emf = Persistence.createEntityManagerFactory("Persistent_Name");
        threadLocal = new ThreadLocal<EntityManager>();
    }

    public static EntityManager getEntityManager() {
        EntityManager em = threadLocal.get();

        if (em == null) {
            em = emf.createEntityManager();
            // set your flush mode here
            threadLocal.set(em);
        }
        return em;
    }

    public static void closeEntityManager() {
        EntityManager em = threadLocal.get();
        if (em != null) {
            em.close();
            threadLocal.set(null);
        }
    }

    public static void closeEntityManagerFactory() {
        emf.close();
    }

    public static void beginTransaction() {
        getEntityManager().getTransaction().begin();
    }

    public static void rollback() {
        getEntityManager().getTransaction().rollback();
    }

    public static void commit() {
        getEntityManager().getTransaction().commit();
    }
}
31
Makky

エンティティーマネージャーはスレッドセーフではなく(ソース Java EE 6チュートリアル )、スレッド間で共有できません。各スレッドは独自のエンティティマネージャーを使用する必要があります。そうしないと、clear()またはclose()の呼び出しに関係なく、問題が発生します。

ただし、インジェクターが各スレッドに独自のエンティティマネージャーを挿入している場合、問題はありません。

Springおよび場合によっては他のDIフレームワークは、実際のエンティティマネージャーのThreadLocalベースのプロキシをBeanに挿入します。各スレッドが行う呼び出しは、エンティティマネージャーの実際のスレッドローカルインスタンスにプロキシします。これは、エンティティマネージャーが複数のスレッド間で共有されているように見えても、動作する方法です。

エンティティマネージャーがどのように注入されるかについての詳細(Springなど)が役立ちます

13
prunge

EntityManagerの管理には、コンテナ管理とアプリケーション管理の2つのタイプがあります。アプリケーション管理の場合、EntityManagerを取得するための推奨メソッドはEntityManagerFactoryを使用することです。 Java EEチュートリアルはこれを言っています:

コンテナ管理エンティティマネージャー

コンテナ管理のエンティティマネージャーを使用すると、EntityManagerインスタンスの永続化コンテキストは、単一のJava Transaction API(JTA)トランザクション内でEntityManagerインスタンスを使用するすべてのアプリケーションコンポーネントにコンテナによって自動的に伝達されます。

通常、JTAトランザクションには、アプリケーションコンポーネント全体の呼び出しが含まれます。 JTAトランザクションを完了するには、これらのコンポーネントは通常、単一の永続コンテキストにアクセスする必要があります。これは、javax.persistence.PersistenceContextアノテーションによってEntityManagerがアプリケーションコンポーネントに注入されたときに発生します。永続コンテキストは現在のJTAトランザクションで自動的に伝播され、同じ永続ユニットにマップされたEntityManager参照は、そのトランザクション内の永続コンテキストへのアクセスを提供します。永続コンテキストを自動的に伝播することにより、アプリケーションコンポーネントは、単一のトランザクション内で変更を行うためにEntityManagerインスタンスへの参照を相互に渡す必要がなくなります。 Java EEコンテナは、コンテナ管理のエンティティマネージャのライフサイクルを管理します。

EntityManagerインスタンスを取得するには、エンティティマネージャーをアプリケーションコンポーネントに挿入します。

@PersistenceContext 
EntityManager em; 

アプリケーション管理エンティティマネージャー

一方、アプリケーション管理のエンティティマネージャーでは、永続化コンテキストはアプリケーションコンポーネントに伝播されず、EntityManagerインスタンスのライフサイクルはアプリケーションによって管理されます。

アプリケーション管理のエンティティマネージャーは、特定の永続性ユニットのEntityManagerインスタンス間でJTAトランザクションによって伝播されない永続性コンテキストにアプリケーションがアクセスする必要がある場合に使用されます。この場合、各EntityManagerは新しい分離された永続コンテキストを作成します。 EntityManagerとそれに関連する永続コンテキストは、アプリケーションによって明示的に作成および破棄されます。また、EntityManagerインスタンスはスレッドセーフではないため、EntityManagerインスタンスを直接注入できない場合にも使用されます。 EntityManagerFactoryインスタンスはスレッドセーフです。

http://docs.Oracle.com/javaee/6/tutorial/doc/bnbqw.html

4
gerrytan

通常、データベースオブジェクトを使用して行う処理にはトランザクションがあります。他のスレッドによって加えられた変更について各スレッドが見るものは、「トランザクション分離」設定によって制御されます。

さまざまな分離設定について学び、ニーズに応じて適切な設定を適用します。精度と速度の間にはトレードオフがあります。 http://en.wikipedia.org/wiki/Isolation_%28database_systems%29

1
n0rm1e

私は3年かそこらです:)が、EJBにEntityManagerを挿入することに関しては、ここにAdam Bienのブログエントリへのリンクがあります http://www.adam-bien.com/roller/abien/entry/is_in_an_ejb_injected

そこからコピーして貼り付けます:

「EntityManagerを直接EJBに挿入できます。ただし、スレッドセーフですか?:

@Stateless
public class BookServiceBean implements BookService {


  @PersistenceContext EntityManager em;

  public void create(Book book) { this.em.persist(book);}

 }

そして答えは、もう一度コピーして貼り付けます:

"1つまたは複数のメソッドを同時に呼び出すかどうかに関係なく、追加の設定なしでEJBを操作することはスレッドセーフです。コンテナは呼び出しのシリアル化を考慮します。"、

これはおそらくより明確になる可能性がありますが、EntityManagerをステートレスセッションBeanに挿入でき、EntityManagerの同時実行の問題を心配する必要がないことを意味します。

0
John Donn