6

約10個のEntityManagerを備えたJavaEEアプリケーションがあります(EMの数はおそらく増えるでしょう)。私のアプリケーションには、ステートレス、ステートフル、メッセージ駆動型のBeanも多数含まれています。

EMを各Beanに注入する@PersistenceContext(およびユーザーに使用するEMを検出する2つの方法)のではなく、おそらくすべてをシングルトンBean内に格納し、他のBeanでアクセスします。そのように、保守性の心配はありません。

それでも、EMを1つのシングルトンBean内に格納することはスレッドセーフですか?ボトルネックは発生しますか?

別の解決策は、抽象クラスを作成することであり、すべてのBeanがそれを拡張します。

より良い解決策は何ですか?

4

3 に答える 3

5

エンティティマネージャはスレッドセーフであるとは想定されていないため、シングルトンを介してエンティティマネージャを共有しないでください。これは、エンティティマネージャをサーブレットに挿入してはならない理由、およびそのようなWebコンポーネントでのJNDIからのルックアップがエンティティマネージャの異なるインスタンスを常に返す必要がある理由と同じ理由です。

実際には、一部の実装ではスレッドセーフなエンティティマネージャーが提供される場合があるため、テスト中には機能しているように見える場合があります。ただし、移植性とアップグレードの問題からユーザーを保護するために、これに依存しないでください。

共通の基本クラスから継承する代わりに、すべてのエンティティマネージャーを1つのBeanで定義し、エンティティマネージャーが必要な場所にそれを注入することができます。

例えば

@Stateless
public class EntityManagerProviderBean {

    @PersistenceContext(unitName="foo")
    private EntityManager entityManagerFoo;

    @PersistenceContext(unitName="bar")
    private EntityManager entityManagerBar;

    public EntityManager getEntityManager() {
        return ...? entityManagerFoo : entityManagerBar;
    }
}

(ここで...は、適切なエンティティマネージャーを選択するために使用するロジックです)

エンティティマネージャを必要とするBeanにこれを注入します。

@Stateless
public class MyService {

    @EJB
    private EntityManagerProviderBean entityManagerProvider;

    public void doStuff(MyEntity myEntity) {
        entityManagerProvider.getEntityManager().update(myEntity);
    }

}

あるいは、次の方がおそらくもっときれいでしょう:

@Stateless
@PersistenceContexts({ 
    @PersistenceContext(unitName="foo", name = "fooENC"),
    @PersistenceContext(unitName="bar", name = "barENC") }
)
public class EntityManagerProviderBean {

    @Resource
    private EJBContext context;

    public EntityManager getEntityManager() {
        return (EntityManager) context.lookup(... ? "fooENC" : "barENC");
    }
}

最後の例では、すべての永続コンテキストをBeanのENCにマップし、プログラムで便利に取得できるようにします。

残念ながら、人々は後者の構文のテストをTCKに追加するのを忘れ、その後、主要ベンダーはそれを実装するのを忘れました(http://java.net/jira/browse/JPA_SPEC-38およびhttps://issues.jboss.org/を参照)。ブラウズ/AS7-5549)、これがサーバーで機能するかどうかをテストします。

于 2012-12-07T22:03:28.123 に答える
2

コンテナ管理エンティティマネージャは、現在のJTAトランザクションで自動的に伝播EntityManagerされ、同じ永続性ユニットにマップされた参照は、そのトランザクション内の永続性コンテキストへのアクセスを提供します。したがって、同時実行性の問題は別として、シングルトンからエンティティマネージャーを共有することはお勧めできません。その結果、Beanで呼び出すすべてのメソッドに同じトランザクションコンテキストが使用されることになります。
ニーズに対する簡単な解決策はEntityManagerFactory、Beanに参照を挿入しEntityManager、メソッドを呼び出すオブジェクトを作成することcreateEntityManager()です。欠点は、コンテナに依存することなく、トランザクションを手動で管理する必要があることです。
それ以外の場合は、別のアプローチとして、すべてのエンティティマネージャーをメインのエンタープライズBeanに挿入し、適切なマネージャーを渡すメソッドを使用してサービスBeanにビジネスロジックを実装することができます。後者の解決策の例:

@Stateless
class MainBean {
    @PersistenceContext EntityManager em1;
    @PersistenceContext EntityManager em2;
    ...
    @EJB WorkerBean1 workerBean1;
    @EJB WorkerBean2 workerBean2;
    ...
    void method1(Object param1, Object param2) {
        workerBean1.method1(em1, param1, param2);
    }

    void method2(Object param1, Object param2, Object param3) {
        workerBean2.method2(em2, param1, param2, param3);
    }
    ...
}

@Stateless
class WorkerBean1 {
    void method1(EntityManager em, Object param1, Object param2) {
        ...
    }
    ...
}

@Stateless
class WorkerBean2 {
    void method2(EntityManager em, Object param1, Object param2, Object param3) {
        ...
    }
    ...
}
于 2012-12-04T09:44:57.073 に答える
1

複合永続性ユニット-JavaEE

Java EEで複数のエンティティマネージャ、つまり複数の永続性ユニットを処理する方法は、複合永続性ユニット(CPU)を使用することです。このような複合永続性ユニットは、EEWebアプリケーションの1つのポイントであるデータレイヤーから評価できます。@Statelessを使用するには、これはEEBeanである必要があります@PersistenceContext

さまざまなJavaアプリケーション間でエンティティクラスを再利用できるようにするために、複合永続ユニットが導入されました。CPUはエンタープライズアーキテクチャの機能です。私はEclipseLinkをショーケースとして使用することを選択しました。これは、実行中の本番アプリケーションからの経験があるためです。

序章

場合によっては、エンティティには、サーバーランドスケープ内のより多くのWebサービスで必要となる一般的なデータが含まれています。たとえば、一般的な「name-address」エンティティ、「user-password-role」エンティティ、「document-keyword-index」エンティティなどを取り上げます。複合永続性ユニットの実装により、各エンティティ定義のソースを次のように指定できます。 1つの場所のみ(「単一の定義ポイント」)。これらのエンティティ定義は、その後、このエンティティアクセスを必要とする各JavaWebアプリケーションに含めることができます。

複合永続性ユニットの動作

複合永続性ユニットの動作は、次のチュートリアルで説明されています。EclipseLink複合永続性ユニット

複合永続性ユニットの概念は、最初にメンバー永続性ユニットを定義することによって機能します。各メンバー永続性ユニットは異なるデータベースに関連付けることができますが、メンバー永続性ユニットはすべて同じ実際のデータベースを参照することもできます。私は後者の経験があり、EclipseLink(バージョン2.6.4)が1つのPostgressデータベースと組み合わせて使用​​されました。

Mavenは、必要なモジュラーアプローチを可能にするために必要です。

persistence.xmlの設定

複合永続ユニットメンバーは、次のように定義され@Entityます。専用のMavenモジュールで、関連するエンティティ(Javaクラス)のグループを1つずつプログラムします。このMavenモジュールで、複合永続ユニットメンバーも定義します(重要です!)。複合ユニットメンバーPuPersonDataは、個人データを特徴付けるこの関連エンティティのセットを参照します。メンバー永続性ユニットPuPersonDataを(

<persistence-unit name="PuPersonData" transaction-type="JTA">
...
    <jta-data-source>jdbc/PostgresDs</jta-data-source>
...

)。

2番目のMavenモジュールで、別の複合永続性ユニットメンバーであるPuWebTraffic(

<persistence-unit name="PuWebTraffic" transaction-type="JTA">
...
    <jta-data-source>jdbc/PostgresDs</jta-data-source>
...

)。ここ@Entityに、Webトランザクション、ログオン、セッションなどに関するデータを格納する他のエンティティ(で示されるJavaクラス)を含めます。言うまでもなく、2つの複合永続性ユニットメンバーはエンティティに関して分離されている必要があり、エンティティ名で重複することはできません。 。

両方の永続性ユニットのメンバーは、XML定義に次のプロパティを持っています。

<properties>
    <property name="eclipselink.composite-unit.member" value="true"/>
    ...
</properties>

複合永続性ユニット

ここで、3番目のMavenモジュールで、永続性ユニットのメンバーであるPuPersonDataとPuWebTrafficの両方を含む複合永続性ユニットCPuPersonSessionDataを定義します。

<persistence-unit name="CPuPersonSessionData" transaction-type="JTA">

この複合永続ユニットCPuPersonSessionDataは、関連する2つのMavenモジュールのコンパイルから生じるjarを含めることにより、2つの永続ユニットメンバーであるPuPersonDataとPuWebTrafficを参照します。

...
    <jar-file>PuPersonData.jar</jar-file>
    <jar-file>PuWebTraffic.jar</jar-file>
...

複合永続性ユニットのXML定義では、次のプロパティを設定する必要があります

<properties>
    <property name="eclipselink.composite-unit" value="true"/>
    ...
</properties>

この設定により、複合永続性ユニットがJavaEEによってその永続性ユニットメンバーとは異なる方法で処理されるようになります。

Javaでの永続性ユニットの使用

個人データとトラフィックデータの両方を含むエンティティを格納および取得するJavaWebアプリケーションには、複合永続性ユニットのみが含まれます。

@Stateless
public class DataLayer {

    @PersistenceUnit(unitName="CPuPersonSessionData")
    EntityManager em; 
    ...

などの通常の「em」操作は、複合エンティティメンバーの1つに含まれる各エンティティで実行できるようになりましpersistfindmerge

Payaraの下では、この複合永続性ユニットが各永続性ユニットメンバーに関連するエンティティに対処するためにXAトランザクションは必要ありませんでした。

Maven

MavenのPOMファイルには、関連するモジュールの仕様が含まれている必要があります。

...
    <modules>
            <module>PersonData</module>
            <module>WebTraffic</module>
            <module>PersonSessionData</module>
    </modules>
...

各モジュールのPOMファイルは、親POMファイルを参照して、通常のMavenプロジェクトとして構成する必要があります。

落とし穴:

  • Mavenマルチモジュールプロジェクトを正しく構成する必要がありますが、これには多少注意が必要です。各複合永続ユニットメンバーは、個別のMavenモジュールを構成します。また、複合永続性ユニットは別個のMavenモジュールです。メンバーは、最初にMavenシーケンスでコンパイルする必要があります。
  • 複合永続ユニットのモジュールをコンパイルするときに、複合永続ユニットの「jar」を見つける必要があります。
  • 各複合永続ユニットメンバーのエンティティは、結果の「jar」で直接「classes」ディレクトリにある必要があります(Mavenを介してエンティティにパスを追加することは可能ですが、複雑です)。
  • 永続性ユニットのメンバーの「jar」は、複合永続性ユニットがそれらを見つけるために「classes」ディレクトリで使用可能である必要があります。

得られる利点は、それぞれが1つの中央定義を持つ再利用可能なエンティティと連携するきちんとしたエンタープライズデータレイヤーです。さらに、ユニット間のネイティブSQLクエリを実行することもできます。これも動作させました。

ドキュメントには、複合永続ユニットのメンバーが異なる実際のデータベースで実行されている場合、ユニット間のネイティブクエリは機能しないと記載されています。これはまだ確認する必要があります。

于 2017-05-04T15:02:25.997 に答える