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.62.0を使用してテストを行っている。 バージョンを変更する場合は、プロジェクト側でテストを行い問題ないことを確認すること。
Domaアダプタを使用するための設定を行う¶
本アダプタを使用するための手順を以下に示す。
依存関係の設定¶
以下を参考にプロジェクトの依存関係を設定する必要がある。
詳細は Doma2でのMavenビルド設定(外部サイト) を参照。
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<annotationProcessorPaths>
<path>
<groupId>org.seasar.doma</groupId>
<artifactId>doma-processor</artifactId>
<version>2.62.0</version>
</path>
</annotationProcessorPaths>
<!-- Eclipseを使用する場合は、 以下の引数を設定すること
<compilerArgs>
<arg>-Adoma.resources.dir=${project.basedir}/src/main/resources</arg>
</compilerArgs>
-->
</configuration>
</plugin>
</plugins>
</build>
使用するRDBMSに合わせて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
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");
}
補足
Doma 2.44.0よりDaoアノテーションのconfig属性が非推奨になったため、Doma 2.44.0以前に案内していた内容から実装方法を変更している。 詳しくは、 Doma 2.44.0までの実装方法から移行する を参照すること。
別トランザクションで実行する¶
Transactional インターセプタによって開始されたトランザクションではなく、 別のトランザクションを使用してデータベースアクセスを行いたい場合がある。
その場合は、 DomaConfig#getTransactionManager で取得した TransactionManager を使用して別トランザクションで制御する。
実装例を以下に示す。
DomaConfig.singleton()
.getTransactionManager()
.requiresNew(() ->
DomaDaoRepository.get(ProjectDao.class).insert(project);
Jakarta Batchに準拠したバッチアプリケーションで使用する¶
Jakarta Batchに準拠したバッチアプリケーションでDomaを使用するために、 本アダプタでは以下のリスナーを提供している。
これらのリスナーをリスナーリストに定義することで、 Jakarta Batchに準拠したバッチアプリケーションでも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);
Jakarta Batchに準拠したバッチアプリケーションで遅延ロードを行う¶
Jakarta Batchに準拠したバッチアプリケーションで大量データの読み込みを行う際に、遅延ロードを使用したい場合がある。
その場合は、Daoの実装クラスをルックアップする際に DomaDaoRepository#get(java.lang.Class,java.lang.Class) を使用し、第2引数に DomaTransactionNotSupportedConfig のClassクラスを指定する。
重要
引数が1つの DomaDaoRepository#get(java.lang.Class) を使用した場合は DomaConfig が使用されるため、 DomaTransactionItemWriteListener によるトランザクションのコミットでストリームがクローズされるため、後続のレコードが読み込めなくなってしまう。
実装例を以下に示す。
- Daoインタフェース
- ポイント
- 検索結果は Stream で取得する。
@Dao public interface ProjectDao { @Select(strategy = SelectType.RETURN) Stream<Project> search(); }
- ItemReaderクラス
- ポイント
- Daoの実装クラスを取得する際に DomaDaoRepository#get(java.lang.Class,java.lang.Class) を使用し、第2引数に DomaTransactionNotSupportedConfig を指定する。
- 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, DomaTransactionNotSupportedConfig.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(); } }
補足
Doma 2.44.0よりDaoアノテーションのconfig属性が非推奨になったため、Doma 2.44.0以前に案内していた内容から実装方法を変更している。 詳しくは、 Doma 2.44.0までの実装方法から移行する を参照すること。
複数のデータベースにアクセスする¶
複数のデータベースにアクセスする必要がある場合は、新しくConfigクラスを作成し、 別のデータベースへのアクセスはそのConfigクラスを使用して行うように実装する。
実装例を以下に示す。
- コンポーネント設定ファイル
<component name="customDomaDialect" class="org.seasar.doma.jdbc.dialect.OracleDialect" /> <component name="customDataSource" class="oracle.jdbc.pool.OracleDataSource"> <!-- プロパティは省略 --> </component>
- Configクラス
- ポイント
- Domaの提供するConfigインターフェースを実装すること。
- 可視性がpublicで引数なしのコンストラクタを持つこと。
public final class CustomConfig implements Config { public CustomConfig() { dialect = SystemRepository.get("customDomaDialect"); localTransactionDataSource = new LocalTransactionDataSource(SystemRepository.get("customDataSource")); localTransaction = localTransactionDataSource.getLocalTransaction(getJdbcLogger()); localTransactionManager = new LocalTransactionManager(localTransaction); } // その他のフィールド、メソッドはDomaConfigを参考に実装すること }
- Daoインタフェース
@Dao public interface ProjectDao { // 省略 }
- 業務アクションクラス
- ポイント
- Daoの実装クラスを取得する際に、 DomaDaoRepository#get(java.lang.Class,java.lang.Class) を使用し、第2引数に作成したConfigクラスを指定する。
public HttpResponse create(final HttpRequest request, final ExecutionContext context) { final Project project = SessionUtil.delete(context, "project"); CustomConfig.singleton() .getTransactionManager() .requiresNew(() -> DomaDaoRepository.get(ProjectDao.class, CustomConfig.class).insert(project); return new HttpResponse("redirect://complete"); }
補足
Doma 2.44.0より作成するConfigへのSingletonConfigアノテーションの付与およびDaoアノテーションのconfig属性が非推奨になったため、Doma 2.44.0以前に案内していた内容から実装方法を変更している。 詳しくは、 Doma 2.44.0までの実装方法から移行する を参照すること。
DomaとNablarchのデータベースアクセスを併用する¶
データベースアクセスにDomaを採用した場合でも、 Nablarch提供のデータベースアクセス を使用したい場合がある。 例えば、 メール送信ライブラリ を使用する場合が該当する。(メール送信要求 で データベースアクセス(JDBCラッパー) を使用している。)
この問題を解決するため、Nablarchのデータベースアクセス処理が、Domaと同じトランザクション(データベース接続)を使用できる機能を提供している。
- 利用手順
コンポーネント設定ファイルに以下の定義を追加する。 これにより、Nablarchのデータベースアクセスが、自動的にDomaのトランザクション配下で実行されるようにある。
- コンポーネント設定ファイルに ConnectionFactoryFromDomaConnection を定義する。
コンポーネント名は、
connectionFactoryFromDoma
とする。 - Jakarta Batch用のDomaのトランザクションを制御するリスナーに、ConnectionFactoryFromDomaConnectionを設定する。
<!-- コンポーネント名は、connectionFactoryFromDomaとする --> <component name="connectionFactoryFromDoma" class="nablarch.integration.doma.ConnectionFactoryFromDomaConnection"> <!-- プロパティに対する設定は省略 --> </component> <!-- Jakarta Batchに準拠したバッチアプリケーションで使用する場合は、Domaのトランザクションを制御するリスナーに 上記で定義したconnectionFactoryFromDomaを設定する。 --> <component class="nablarch.integration.doma.batch.ee.listener.DomaTransactionItemWriteListener"> <property name="connectionFactory" ref="connectionFactoryFromDoma" /> </component> <component class="nablarch.integration.doma.batch.ee.listener.DomaTransactionStepListener"> <property name="connectionFactory" ref="connectionFactoryFromDoma" /> </component>
- コンポーネント設定ファイルに ConnectionFactoryFromDomaConnection を定義する。
コンポーネント名は、
ロガーを切り替える¶
本アダプタではDomaが使うロガーの実装として、Nablarchのロガーを使用する NablarchJdbcLogger を提供している。 デフォルトでは NablarchJdbcLogger が使用されるが、他のものに差し替える場合はコンポーネント定義ファイルに設定する必要がある。
org.seasar.doma.jdbc.UtilLoggingJdbcLogger
を使用する場合の設定例を以下に示す。
- ポイント
- 定義するロガーは
org.seasar.doma.jdbc.JdbcLogger
の実装クラスとすること - ロガーのコンポーネント名は
domaJdbcLogger
とすること
- 定義するロガーは
<component name="domaJdbcLogger" class="org.seasar.doma.jdbc.UtilLoggingJdbcLogger" />
java.sql.Statementに関する設定を行う¶
フェッチサイズやクエリタイムアウトなど、 java.sql.Statement
に関する項目をプロジェクト全体に設定したい場合がある。
その場合はコンポーネント設定ファイルに DomaStatementProperties を設定する。
設定できる項目には下記のものがある。
- 最大行数の制限値
- フェッチサイズ
- クエリタイムアウト(秒)
- バッチサイズ
設定例を以下に示す。
- ポイント
- コンポーネント名は
domaStatementProperties
とすること
- コンポーネント名は
<component class="nablarch.integration.doma.DomaStatementProperties" name="domaStatementProperties">
<!-- 最大行数の制限値を1000行に設定する -->
<property name="maxRows" value="1000" />
<!-- フェッチサイズを200行に設定する -->
<property name="fetchSize" value="200" />
<!-- クエリタイムアウトを30秒に設定する -->
<property name="queryTimeout" value="30" />
<!-- バッチサイズを400に設定する -->
<property name="batchSize" value="400" />
</component>
Doma 2.44.0までの実装方法から移行する¶
Doma 2.44.0より(外部サイト、英語) Daoアノテーションのconfig属性およびSingletonConfigアノテーションが非推奨となったことにより、NablarchでもAPIを追加し、案内していた内容から実装方法を変更している。
引き続きDaoアノテーションのconfig属性およびSingletonConfigアノテーションを使用した実装も動作するが、Domaの変更に合わせて実装方法を移行することを推奨する。
ここではDoma 2.44.0以前にNablarchで案内していた実装方法との対比を説明する。
なお、Doma 2.44.0以前に案内していた実装方法でも引き続き同じ動作を行う。
DomaConfigを使った基本的な実装をしている場合¶
Daoアノテーションのconfig属性に DomaConfig を使用した実装例を以下に示す。
// Daoの定義
@Dao(config = DomaConfig.class) /* config属性を指定 */
public interface ProjectDao {
// 省略
}
// Daoを使用する実装例
@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");
}
これは以下の実装と等価となる。
// Daoの定義
@Dao /* config属性の指定を削除 */
public interface ProjectDao {
// 省略
}
// Daoを使用する実装例
@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");
}
Daoアノテーションのconfig属性を指定しないDaoを使用して DomaDaoRepository#get を使ってDaoの実装クラスを取得した場合、 DomaConfig を使用してDaoの実装クラスが構築される。
DomaTransactionNotSupportedConfigを使用して遅延ロードに対応している場合¶
Jakarta Batchに準拠したバッチアプリケーションで遅延ロードに対応するため、 DomaTransactionNotSupportedConfig を使用した実装例を以下に示す。
// Daoの定義
@Dao(config = DomaTransactionNotSupportedConfig.class) /* config属性を指定 */
public interface ProjectDao {
@Select(strategy = SelectType.RETURN)
Stream<Project> search();
}
// Daoを使用する実装例
@Dependent
@Named
public class ProjectReader extends AbstractItemReader {
private Iterator<Project> iterator;
private Stream<Project> stream;
@Override
public void open(Serializable checkpoint) throws Exception {
/* DomaDaoRepository#getにはDaoのインターフェースのみを指定 */
final ProjectDao dao = DomaDaoRepository.get(ProjectDao.class);
stream = dao.search();
iterator = stream.iterator();
}
// 省略
}
これは以下の実装と等価となる。
// Daoの定義
@Dao /* config属性の指定を削除 */
public interface ProjectDao {
@Select(strategy = SelectType.RETURN)
Stream<Project> search();
}
// Daoを使用する実装例
@Dependent
@Named
public class ProjectReader extends AbstractItemReader {
private Iterator<Project> iterator;
private Stream<Project> stream;
@Override
public void open(Serializable checkpoint) throws Exception {
/* DomaDaoRepository#getの第2引数にDomaTransactionNotSupportedConfig.classを指定 */
final ProjectDao dao = DomaDaoRepository.get(ProjectDao.class, DomaTransactionNotSupportedConfig.class);
stream = dao.search();
iterator = stream.iterator();
}
// 省略
}
Daoアノテーションにconfig属性を指定しないDaoを使用して DomaDaoRepository#get(java.lang.Class,java.lang.Class) を呼び出した場合、第2引数に指定したConfigを使用してDaoの実装クラスが構築される。
独自にConfigクラスを作成している場合¶
複数のデータベースにアクセスする等の理由で、独自にConfigクラスを作成して実装する例を以下に示す。
// Configクラスの定義
@SingletonConfig /* SingletonConfigアノテーションを付与 */
public final class CustomConfig implements Config {
private CustomConfig() { /* コンストラクタはprivate */
// 省略
}
// 省略
}
// Daoの定義
@Dao(config = CustomConfig.class) /* config属性に作成したConfigクラスを指定 */
public interface ProjectDao {
// 省略
}
// Daoを使用する実装例
public HttpResponse create(final HttpRequest request, final ExecutionContext context) {
final Project project = SessionUtil.delete(context, "project");
CustomConfig.singleton()
.getTransactionManager()
.requiresNew(() ->
/* DomaDaoRepository#getにはDaoのインターフェースのみを指定 */
DomaDaoRepository.get(ProjectDao.class);
return new HttpResponse("redirect://complete");
}
これは以下の実装と等価となる。
// Configクラスの定義
/* SingletonConfigアノテーションを削除 */
public final class CustomConfig implements Config {
public CustomConfig() { /* publicな引数なしのコンストラクタに変更 */
// 省略
}
// 省略
}
// Daoの定義
@Dao /* config属性の指定を削除 */
public interface ProjectDao {
// 省略
}
// Daoを使用する実装例
public HttpResponse create(final HttpRequest request, final ExecutionContext context) {
final Project project = SessionUtil.delete(context, "project");
CustomConfig.singleton()
.getTransactionManager()
.requiresNew(() ->
/* DomaDaoRepository#getの第2引数に作成したConfigのClassクラスを指定 */
DomaDaoRepository.get(ProjectDao.class, CustomConfig.class);
return new HttpResponse("redirect://complete");
}
Daoアノテーションにconfig属性を指定しないDaoを使用して DomaDaoRepository#get(java.lang.Class,java.lang.Class) を呼び出した場合、第2引数に指定したConfigを使用してDaoの実装クラスが構築される。