Domaアダプタ¶
目次
Doma2(外部サイト) を使用したデータベースアクセスを行うためのアダプタを提供する。
データベースアクセスにDomaを使用することで以下のメリットが得られる。
- Nablarchと同じように、実行時に動的にSQL文を構築することができる。
- 2waySQLなので、NablarchのようにSQL文を書き換える必要がなく、SQLツール等でそのまま実行することができる。
また、本アダプタを使用することで、 Transactional インターセプタで 指定したアクションのみトランザクション管理対象とすることができるため、 不要なトランザクション制御処理を削減でき、パフォーマンスの向上が期待できる。
モジュール一覧¶
<!-- Domaアダプタ -->
<dependency>
<groupId>com.nablarch.integration</groupId>
<artifactId>nablarch-doma-adaptor</artifactId>
</dependency>
ちなみに
Domaのバージョン2.16.0を使用してテストを行っている。 バージョンを変更する場合は、プロジェクト側でテストを行い問題ないことを確認すること。
Domaアダプタを使用するための設定を行う¶
本アダプタを使用するためには、プロジェクトで使用するRDBMSに合わせてDomaのダイアレクトやデータソースをコンポーネント定義ファイルに設定する必要がある。
H2を使用する場合の設定例を以下に示す。
- ポイント
- 定義するダイアレクトは
org.seasar.doma.jdbc.dialect.Dialect
の実装クラスとすること - ダイアレクトのコンポーネント名は
domaDialect
とすること - データソースのコンポーネント名は
dataSource
とすること
- 定義するダイアレクトは
<component name="domaDialect" class="org.seasar.doma.jdbc.dialect.H2Dialect" />
<component name="dataSource" class="org.h2.jdbcx.JdbcDataSource">
<!-- プロパティは省略 -->
</component>
Domaを使用してデータベースにアクセスする¶
Domaを使用したデータベースアクセスを行うための手順を以下に示す。
Daoインタフェースを作成する¶
データベースアクセスを行うためのDao(Data Access Object)インタフェースを作成する。
- ポイント
- Daoアノテーションのconfig属性には DomaConfig を指定する
@Dao(config = DomaConfig.class)
public interface ProjectDao {
// 省略
}
データベースアクセス処理を実装する¶
業務アクションのメソッドにデータベースアクセス処理を実装する。
- ポイント
- 業務アクションメソッドをトランザクション管理対象とするため、 Transactional インターセプタを設定する
- DomaDaoRepository#get を使用してDaoの実装クラスをルックアップする
ちなみに
Domaでは注釈処理によってコンパイル時に自動的にDaoの実装クラスが生成されるため、コーディング時にはまだ実装クラスが存在しない。 そのため、本アダプタではDaoの実装クラスをルックアップする機能として DomaDaoRepository を提供している。
@Transactional
public HttpResponse create(final HttpRequest request, final ExecutionContext context) {
final Project project = SessionUtil.delete(context, "project");
DomaDaoRepository.get(ProjectDao.class).insert(project);
return new HttpResponse("redirect://complete");
}
別トランザクションで実行する¶
Transactional インターセプタによって開始されたトランザクションではなく、 別のトランザクションを使用してデータベースアクセスを行いたい場合がある。
その場合は、 DomaConfig#getTransactionManager で取得した TransactionManager を使用して別トランザクションでの制御を行う。
実装例を以下に示す。
DomaConfig.singleton()
.getTransactionManager()
.requiresNew(() ->
DomaDaoRepository.get(ProjectDao.class).insert(project);
JSR352に準拠したバッチアプリケーションで使用する¶
JSR352に準拠したバッチアプリケーションでDomaを使用するために、 本アダプタでは以下のリスナーを提供している。
これらのリスナーをリスナーリストに定義することで、 JSR352に準拠したバッチアプリケーションでもDomaを使用したデータベースアクセスを行うことができる。
設定例を以下に示す。
<list name="stepListeners">
<!-- その他のリスナーは省略 -->
<component class="nablarch.integration.doma.batch.ee.listener.DomaTransactionStepListener" />
</list>
<list name="itemWriteListeners">
<!-- その他のリスナーは省略 -->
<component class="nablarch.integration.doma.batch.ee.listener.DomaTransactionItemWriteListener" />
</list>
重要
Chunkステップ のItemWriterでデータベースに対するバッチ更新(バッチinsertやバッチupdateなど)を行う場合、バッチサイズの指定を明示的に行う必要がある。 ※Chunkステップのitem-countのサイズがバッチサイズとなるわけではないので注意すること
これを行わなかった場合、Domaのデフォルト値が適用されるため、バッチ更新を使用してもパフォーマンスが向上しない可能性がある。
- 実装例
例えば、1000件ごとにバッチinsertを行う場合には、Daoのメソッドを以下のように実装する。
@BatchInsert(batchSize = 1000) int[] batchInsert(List<Bonus> bonuses);
JSR352に準拠したバッチアプリケーションで遅延ロードを行う¶
JSR352に準拠したバッチアプリケーションで大量データの読み込みを行う際に、遅延ロードを使用したい場合がある。
その場合は、Daoアノテーションのconfig属性に DomaTransactionNotSupportedConfig を指定する。
重要
config属性に DomaConfig を使用すると、 DomaTransactionItemWriteListener によるトランザクションのコミットでストリームがクローズされるため、後続のレコードが読み込めなくなってしまう。
実装例を以下に示す。
- Daoインタフェース
- ポイント
- Daoアノテーションのconfig属性には、 DomaTransactionNotSupportedConfig を指定する。
- 検索結果は Stream で取得する。
@Dao(config = DomaTransactionNotSupportedConfig.class) public interface ProjectDao { @Select(strategy = SelectType.RETURN) Stream<Project> search(); }
- ItemReaderクラス
- ポイント
- openメソッドで検索結果のストリームを取得する。
- リソースの解放漏れを防ぐため、closeメソッドで必ずストリームを閉じる。
@Dependent @Named public class ProjectReader extends AbstractItemReader { private Iterator<Project> iterator; private Stream<Project> stream; @Override public void open(Serializable checkpoint) throws Exception { final ProjectDao dao = DomaDaoRepository.get(ProjectDao.class); stream = dao.search(); iterator = stream.iterator(); } @Override public Object readItem() { if (iterator.hasNext()) { return iterator.next(); } else { return null; } } @Override public void close() throws Exception { stream.close(); } }
ETLで使用する¶
ETL使用時に、プロジェクトで追加したステップの中でDomaを使用したい場合がある。 その場合は、ジョブ名およびステップ名を指定したリスナーリストを定義して対応する。
設定例を以下に示す。
- ジョブ定義ファイル
<job id="sampleJob" xmlns="http://xmlns.jcp.org/xml/ns/javaee" version="1.0"> <step id="sampleStep"> <listeners> <listener ref="nablarchStepListenerExecutor" /> <listener ref="nablarchItemWriteListenerExecutor" /> </listeners> <chunk> <reader ref="sampleItemReader" /> <writer ref="sampleItemWriter" /> </chunk> </step> </job>
- コンポーネント定義ファイル
<list name="sampleJob.sampleStep.stepListeners"> <!-- その他のリスナーは省略 --> <component class="nablarch.integration.doma.batch.ee.listener.DomaTransactionStepListener" /> </list> <list name="sampleJob.sampleStep.itemWriteListeners"> <!-- その他のリスナーは省略 --> <component class="nablarch.integration.doma.batch.ee.listener.DomaTransactionItemWriteListener" /> </list>
複数のデータベースにアクセスする¶
複数のデータベースにアクセスする必要がある場合は、新しくConfigクラスを作成し、 別のデータベースへのアクセスはそのConfigクラスを使用して行うように実装する。
実装例を以下に示す。
- コンポーネント定義ファイル
<component name="customDomaDialect" class="org.seasar.doma.jdbc.dialect.OracleDialect" /> <component name="customDataSource" class="oracle.jdbc.pool.OracleDataSource"> <!-- プロパティは省略 --> </component>
- Configクラス
@SingletonConfig public final class CustomConfig implements Config { private CustomConfig() { dialect = SystemRepository.get("customDomaDialect"); localTransactionDataSource = new LocalTransactionDataSource(SystemRepository.get("customDataSource")); localTransaction = localTransactionDataSource.getLocalTransaction(getJdbcLogger()); localTransactionManager = new LocalTransactionManager(localTransaction); } // その他のフィールド、メソッドはDomaConfigを参考に実装すること }
- Daoインタフェース
@Dao(config = CustomConfig.class) public interface ProjectDao { // 省略 }
- 業務アクションクラス
public HttpResponse create(final HttpRequest request, final ExecutionContext context) { final Project project = SessionUtil.delete(context, "project"); CustomConfig.singleton() .getTransactionManager() .requiresNew(() -> DomaDaoRepository.get(ProjectDao.class).insert(project); return new HttpResponse("redirect://complete"); }