将来的にはJavaEEの仕様にマルチテナント機能が組み込まれますが、
僕は今のところ、複数データソースの切り替えが出来れば十分なので、
CDIを使ってやってみました。
これで1つのJavaEE6アプリで複数のデータベースへの接続を切り替える事が可能です。

では早速、実際のソースを見てみましょう。

 

まずはプロデューサ・メソッドから。
EntityManagerがDIされるフィードを複数持ち、プロデューサ・メソッドで何れかをreturnします。
今回の例ではシステム日付の秒で分岐しましたが、
実際はURLパラメータやCookieに保持した値などで分岐する事になると思います。
また、RequestScopedアノテーションを付けて、リクエスト毎に呼ばれるようにします。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public class EntityManagerFactory {

    @PersistenceContext(unitName = "pu01")
    private EntityManager em01;
    @PersistenceContext(unitName = "pu02")
    private EntityManager em02;

    @RequestScoped
    @Produces
    @EntityManagerQualifier
    public EntityManager getEntityManager() {
        // システム日付が偶数秒ならem01に接続する。
        DateTime dt = new DateTime();
        int sec = Integer.parseInt(dt.toString("s"));
        if (sec % 2 == 0) {
            return em01;
        } else {
            return em02;
        }
    }
}

次にDIでEntityManagerを受け取る側
DIで受け取ったEntityManagerを使うだけです。
今回の例ではコントローラに書いてます。

1
2
3
4
5
6
7
8
9
10
11
12
@Model
public class SampleController {

    @Inject
    @EntityManagerQualifier
    private EntityManager em;

    public String getName() {
        Query query = em.createNamedQuery("findAll", Sample.class);
        return ((Sample) query.getSingleResult()).getName();
    }
}

EntityManagerQualifierアノテーションはQualifier(限定子)です。
インジェクションの対象を限定(紐付け?)させています。

1
2
3
4
5
@Qualifier
@Retention(RUNTIME)
@Target({METHOD, FIELD, PARAMETER, TYPE})
public @interface EntityManagerQualifier {
}

ソースはGitHubにアップしてます。
READMEに環境構築の手順メモも書いてます。
サンプルソース

以上、久々のJavaネタでした!