複数DB

複数DBとは?

複数DBという言葉はとても曖昧なので、DBFluteとしての解釈をここで厳密に定義します。

  • A. 全く "違う" テーブル構造の別DBを利用
  • B. 全く "同じ" テーブル構造の別DBを利用

基本とする複数DB

DBFluteでは、基本的に "複数DB" と言った場合は "A" を示します。このページでも自動生成環境が複数になる "A" の場合の環境構築に関して説明をします。

冗長化複数DB

一方で、"B" を 冗長化複数DB と呼び、こちらの実現方法は、DIコンテナやトランザクションフレームワークなどに依存します。 逆にDBFluteでは、特に自動生成環境が複数になることはなく(同じテーブル構造のため)、 DIコンテナ経由で利用している javax.sql.DataSource の実装クラスを冗長化複数DB対応のものに差し替えることで実現できます。 (例えば、Seasar(S2Container)であれば、SelectableDataSourceProxyを利用)

複数スキーマは別の機能

また、DBFluteの機能としては、アプリで利用対象となる複数DBに対して、一つのデータソース(DBへのコネクション)でアクセスできるような場合は、"複数DB" はなく、"複数スキーマ" と捉え、(このページで紹介する方法とは)全く別の機能で実現することができます。例えば、メインDBが Oracle で、別に PostgreSQL をサブDBとして利用するような場合は問答無用で "複数DB" です。一方、同じ Oracle インスタンス内の別のスキーマ、もしくは、同じ PostgreSQL インスタンス内の別の(もしくは同じ)データベースのスキーマにおいては "複数スキーマ" となります。"複数スキーマ" は、AdditionalSchema という別の機能が利用でき、そちらで対応するのがお奨めです。(この場合、一つの自動生成環境で複数のスキーマを扱うことができます)

複数DBと複数スキーマの境目

"複数スキーマ" の構成も "複数DB" のやり方で実現することは可能ですが("複数DB" は、"複数スキーマ" を(意味的に)包含します)、もし、複数DB間でFK制約などの関連を持っているような場合は、AdditionalSchema を利用することで、自動生成された Entity 間で関連として(ConditionBeanなどで)扱うことができます。 DB間の業務的な(かつ、実装的な)密接度が高い場合は "複数スキーマ" として取り扱う と良いでしょう。一方で、"複数スキーマ" 構成だとしても、テーブル設計などのやり方・文化などがあまりに違う場合は(例えば、共通カラムの構造が全く違うなど)、 "複数スキーマ" 構成で実現できるにしても、互いに独立した設定をしやすい "複数DB" として扱うのが良いでしょう。

複数DB対応の環境構築

ポイントになる点は以下の通りです。

DBFluteクライアントが複数

DBの個数分、DBFluteクライアントも作成します(DBFluteモジュールは一つでOK)。

e.g. 複数DB対応のDBFluteクライアント構造 {foodb,bardb} @EclipseProject
xxx-project
 |-dbflute_foodb // FooDB用のDBFluteクライアント
 |  |-dfprop
 |  |-log
 |  |-...
 |-dbflute_bardb // BarDB用のDBFluteクライアント
 |  |-dfprop
 |  |-log
 |  |-...
 |-mydbflute
 |     |-dbflute-1.0.0 // 共通のDBFluteモジュール
 |-src/main/java
 |-...

それぞれ自動生成されるクラスをDBごとに違うプロジェクトに配置する場合は、一つのプロジェクトに複数DBFluteクライアントではなく、 それぞれのプロジェクトごとに一つのDBFluteクライアントを作成する構成で問題ありません。 (その構成でDBFluteモジュールを共有させる場合は、_project.sh|bat の参照設定を修正します)

自動生成クラスのパッケージをユニークにする

それぞれの basicInfoMap.dfprop の packageBase をユニークにします。

例えば、単一DBでは "com.example.xxx.dbflute" としていたものを、"...dbflute.foodb" と "...dbflute.bardb" というように設定します。

但し、開発・運用途中で複数DBになった場合は、追加されたDBの方だけを "...dbflute.bardb" とするような構造でも問題ありません(以降、その他プロパティでも同じことが言えます)。

e.g. 複数DB対応のパッケージ構造 {foodb,bardb} @EclipseProject
xxx-project
 |-dbflute_foodb
 |-dbflute_bardb
 |-mydbflute
 |     |-dbflute-1.0.0
 |-src/main/java
 |  |-com.example.xxx.dbflute.foodb // FooDB用のパッケージ
 |  |  |-allcommon
 |  |  |-bsbhv
 |  |  |-...
 |  |-com.example.xxx.dbflute.bardb // FooDB用のパッケージ
 |  |  |-allcommon
 |  |  |-bsbhv
 |  |  |-...
 |-...

DI設定ファイルの名前をユニークにする

それぞれの dependencyInjectionMap.dfprop の "利用しているDIコンテナに対応するDI設定ファイル名のプロパティ" をユニークにします。例えば、Seasar(S2Container) なら dbfluteDiconFileName、Spring Framework なら dbfluteBeansFileName

現場フィット - DIEnvironment - DI設定ファイル名
e.g. 複数DB対応のDI設定ファイル {foodb,bardb,Seasar(S2Container)} @EclipseProject
xxx-project
 |-dbflute_foodb
 |-dbflute_bardb
 |-mydbflute
 |     |-dbflute-1.0.0
 |-src/main/java
 |-src/main/resources
 |  |-dbflute-foodb.dicon // FooDB用のdbflute.dicon
 |  |-dbflute-bardb.dicon // BarDB用のdbflute.dicon
 |-...

DI設定ファイルがクラス形式になっているDIコンテナに関しては、パッケージが別になっているのでこの設定は不要です。 (例えば、Google Guice など)

また、ファイル形式であっても、プロジェクト構成上、同じファイル名であってもユニークに扱われるようになっているのであれば、 この設定は不要です。

DI設定ファイル内の DataSource 参照をユニークにする

それぞれの dependencyInjectionMap.dfprop の "利用しているDIコンテナに対応するDataSource参照のプロパティ" をユニークにします。例えば、Seasar(S2Container) なら j2eeDiconResourceName、Spring Framework なら dbfluteBeansDataSourceName

現場フィット - DIEnvironment - DataSource
e.g. 複数DB対応のDI設定ファイルのDataSource参照 {foodb,Seasar(S2Container)} @dbflute-foodb.dicon
<components namespace="dbflute">
    <include path="j2ee-foodb.dicon"/>
...
e.g. 複数DB対応のDI設定ファイルのDataSource参照 {foodb,Spring Framework} @dbfluteBeansFooDb.xml
<bean id="foInvokerAssistant" class="...ImplementedInvokerAssistant" ...">
    <property name="dataSource"><ref bean="fooDbDataSource"/></property>
    ...
</bean>

クラス名の prefix を(必要であれば)設定する

それぞれの basicInfoMap.dfprop の projectPrefix をユニークにします。但し、これは必須ではありません。別DB同名テーブルが存在する場合 や、別DBであることを実装上明示的に区別したい場合 などに利用します。複数DBが、メインとサブというように業務的に分かられるような場合は、サブのDBの方にだけ設定するのも良いでしょう。

現場フィット - ProjectPrefix

また、これを設定することで、allcommon内のクラスで別パッケージ同名クラスを避けることができます。 そもそも allcommon 内のクラスをアプリで直接利用することは少ないため、別パッケージ同名クラスでも動作的には問題ありませんが、 幾つかの時々利用する可能性のあるクラスにおいて、やはりそれを避けたいのであれば設定することをお奨めします。

e.g. 複数DB対応のクラス名の prefix {Fo,Ba,MEMBER} @EclipseProject
xxx-project
 |-dbflute_foodb
 |-dbflute_bardb
 |-mydbflute
 |-src/main/java
 |  |-com.example.xxx.dbflute.foodb.exentity
 |     |-FoMember.java
 |-src/main/java
 |  |-com.example.xxx.dbflute.bardb.exentity
 |     |-BaMember.java
 |-...

外だしSQLの対象パッケージを(必要であれば)設定する

それぞれの outsideSqlDefinitionMap.dfprop の sqlPackage をユニークにします。通常、Sql2Entity や OutsideSqlTest は、src/main/resources (デフォルト)配下の全てのSQLを対象とするため、別のDBのSQLを処理対象としないようにするために、明示的に設定します。 但し、これは必須ではなく、それぞれ自動生成されるクラスをDBごとに違うプロジェクトに配置する場合は、この設定は不要です。

OutsideSql - OutsideSqlPackage

設定値は、基本的に $$PACKAGE_BASE$$ とだけ設定すれば良いでしょう。

e.g. 複数DB対応のSQLパッケージ {foodb,bardb} @outsideSqlDefinitionMap.dfprop
; sqlPackage = $$PACKAGE_BASE$$

Exampleのススメ

dbflute-multipledb-seasar-example や dbflute-multipledb-spring-example では、実際に複数DBの構成を実現しています。 この構成は複雑な部分があるため、(主に環境面において)必ずExampleを参考にするようにして下さい。

DBFlute Example - 特定環境