2012-03-31 14 views
15

EJBで永続ユニットを動的に指定する方法が必要です。JPA動的永続ユニットの名前

簡略化された例:

データストアとして複数のデータベースを使用するアプリケーションがあります。 各データストアは構造的に同じです。 アプリケーションに接続するクライアントによっては、特定のデータストア のデータにアクセスする必要があります。

したがって、ビジネスロジックが重複しないように同じEJBを使用したいと考えていますが、 が、クライアントに基づいて正しい永続性ユニットを選択するだけです。

これまでは、エンティティマネージャに、永続化ユニット名をハードコードして注入しただけです。 EJBに必要な永続性ユニットを動的に挿入する方法はありますか? また、実行時に永続性ユニットを動的に追加できますか? 現在、persistence.xmlファイルで永続性単位を指定する必要があります。 理想的には、システムの稼働中に、必要に応じてサーバーjdbc/db1、jdbc/db2などにプールを作成したいと考えています。次に、これらを中央のクライアントデータベースに追加してクライアントにリンクするだけで、クライアントが接続するときにプールの名前がチェックされ、永続ユニットを取得するためにEJBを呼び出すときに使用されます。

私はまだJava EE開発の新機能です。どんな助けでも大歓迎です。

答えて

8

現在のJPAバージョンでは、残念ながら永続ユニットを動的に作成することはできません。この機能が重要な場合は、JPA問題追跡ツールでJIRA問題を作成することを検討してください。http://java.net/jira/browse/JPA_SPEC

@PersistenceContextアノテーションを使用すると、特定の永続ユニットを動的に選択することもできません。これは実際にシャーディングのドメインであり、Hibernateはこれまで一度は対処しようとしましたが突然中断しました。 http://www.hibernate.org/subprojects/shards.html

ただし、同様の効果を得るにはいくつかのことがあります。

1つの方法は、ステートレスEJB/CDIファクトリBeanを作成して、すべてのエンティティ・マネージャをインジェクトする方法です。これらのBeanはプールされ、Entity Managerは最初に作成するのに費用がかからないため、このコストはわずかです。

もしあなたが何らかの条件に基づいて注射したいのであれば、この状態は文脈から利用可能でなければならないか、注入ポイントで指定されなければなりません(しかし、そうするならば、右のエンティティマネージャに直接)。

キックオフ例:あなたの豆で

@Stateless 
@TransactionAttribute(SUPPORTS) 
public class ShardingEntityManagerFactory { 

    @Resource 
    private SessionContext sessionContext; 

    @PersistenceContext(unitName = "pu1") 
    private EntityManager entityManager1; 

    @PersistenceContext(unitName = "pu2") 
    private EntityManager entityManager2; 

    @Produces @TransactionScoped @ShardedPersistenceContext 
    public EntityManager getEntityManager() { 
     if (sessionContext.isCallerInRole("FOO")) { 
      return entityManager1; 
     } else { 
      return entityManager2; 
     } 
    } 
} 

そして:あなたは@TransactionScoped注釈のためにここにシーム永続が必要になります

@Stateless 
public class SomeBean { 

    @Inject @ShardedPersistenceContext 
    private EntityManager entityManager; 

    // ... 
} 

注意。エンティティマネージャを透過的に注入することを忘れて、代わりにShardingEntityManagerFactoryを注入して、手作業で正しいものを取得するのは簡単ですが、もう少し冗長になるかもしれません。

+0

これは私が必要とするものですが、各永続性ユニットをSharedEntityManagerFactoryに定義する必要があります。 コードを変更する必要がなく、再デプロイメントを必要としないように、それらを動的に追加できるようにしたいと思います。永続ユニットの詳細をメインデータベースに保存し、必要に応じてクライアントにリンクするだけで済みます。しかしこれは、各データストアを別個のWebサービスとして実装するよりはるかに優れています。ずっと少ないオーバーヘッド。 Webサービスには、URLをdbに格納して動的に使用できるという利点があります。私はオプションを上げる必要があります。 – likenoother

3

これはおそらく、問題を解決するための助け無しのですが、この種の問題は、JPA 2.1

これは、マルチテナントのものを例1のように聞こえるの実装のために検討されていることを知っていただきたいことがあります。

Proposal for Multitenancy Support in JPA 2.1 JSR-338

+0

私はそれが実際にマルチテナントから離れているわけではないと思うのですが、1つのDBが複数のテナント間で共有されているのに対し、1人のテナントは複数のDBを1つに見せたいと考えています。 –

+0

@ArjanTijmsは正しいです。私が探しているのはマルチテナントと似ていますが、1つのデータベースを使う代わりに、データベース以上のものを使いたいと思います。おそらく、各データベースを別々のEJBデプロイメントに分割し、その後にWebサービス経由で接続する価値があります。私はオーバーヘッドが気に入らないのですが、少なくとも必要に応じて異なるシステム間でデータベースをサポートする自由を私に与えます。 異なるマシンにクライアントを格納します。このためにリモートインタフェースを使用できるかどうかは不明です。 – likenoother

+0

@likenoother良い考え方!はい。永続ユニットを実行中のシステムに追加する動的な方法の1つは、EJBモジュール(ejb jar)をASにホットデプロイすることです。ローカルインターフェースを介して技術的に「同じAS上の異なるアプリケーション」からBeanを検索することは指定されていませんが、実際には実際に動作します。これらのBeanを直接インジェクトする代わりに、プログラムによるJNDIルックアップを使用して、動的に追加された永続ユニットをカプセル化するBeanを動的に取得できます。セットアップはちょっとしたことですが、うまくいくかもしれません。 –

1

ジャストアイデアではなく、それに役立つだろうかどうかわから: あなたはpersistence.xmlファイルを読み込み、これらの行を置き換えるためにInputStreamを開くことがあります。

<property name="javax.persistence.jdbc.url" value="jdbc:mysql://localhost:3306/agendasccv2?zeroDateTimeBehavior=convertToNull"/> 
<property name="javax.persistence.jdbc.password" value="btxbtxbtx"/> 
<property name="javax.persistence.jdbc.driver" value="com.mysql.jdbc.Driver"/> 
<property name="javax.persistence.jdbc.user" value="root"/> 

はその後、メインアプリケーション

それが役立つかどうかわからないを開始し、そのファイル上のユーザー権限に応じてユーザがログイン接続設定画面をスプラッシュし、接続を設定し、それだけと考えです。 アプリケーションとビジネスロジックによって異なります。

2

これに同じパーシスタンスユニットを使用できます。使用するurl/datasourceでcreateEntityManagerFactory()を呼び出すときにプロパティマップを提供するだけです。

+0

いいアイデアだが、うまくいきません。 Java EE環境ですか? emファクトリをインジェクトでき​​ますが、createメソッドはJava SE環境用です。 –

関連する問題