はじめに
データベースアクセスに欠かせないトランザクション機能についてポイントを紹介します。
この記事では、Doma 3.6.0を前提とします。
Domaの他の機能紹介についてはDoma入門もお読みください。
最初に検討すること
トランザクションに関して最初に検討すべきことがあります。
それは、利用しているフレームワーク(SpringFrameworkなど)がトランザクション機能を提供しているかどうかです。提供している場合、まずはそちらの利用を検討ください。
SpringFrameworkを使う場合
SpringFrameworkはトランザクション機能を提供します。
org.seasar.doma.jdbc.Config
の実装クラスのgetDataSource
メソッドでは、org.springframework.jdbc.datasource.TransactionAwareDataSourceProxy
を使ってラップしたDataSource
を返すように設定してください。これが非常に重要です。
上記対応を行った上でこのガイドを参考にSpringのコンポーネントのクラスやメソッドに@Transactional
を付与すればトランザクションを利用できます。
doma-spring-bootを使えば上記のDataSource
のラッピングは自動で行われます。doma-spring-bootを使ってSpringFrameworkのトランザクション機能を利用しているサンプルアプリとしてはspring-boot-jpetstoreがあります。
Quarkusを使う場合
Quarkusはトランザクション機能を提供します。
org.seasar.doma.jdbc.Config
の実装クラスのgetDataSource
メソッドでは、Quarkusのコネクションプール実装であるAgroalで管理されたDataSource
を返してください。
上記対応を行った上でこのドキュメントにあるようにCDIのコンポーネントのクラスやメソッドに@Transactional
を付与すればトランザクションを利用できます。
Quarkus Doma Extensionを使えば上記のDataSource
の設定は自動で行われます。Quarkus Doma Extensionを使ってQuarkusのトランザクション機能を利用しているサンプルアプリとしてはquarkus-sampleがあります。
トランザクション機能を提供するフレームワークを使わない場合
Domaのローカルトランザクションの利用を検討してください。
Domaのローカルトランザクションの特徴は次の通りです。
-
ThreadLocal
を使ってスレッドごとにコネクションを管理する - 名前の通りローカルトランザクションなので扱えるリソースは1つだけ(グローバルトランザクションのように2フェーズコミットの機能はない)
- 手続的なAPIである
org.seasar.doma.jdbc.tx.TransactionManager
を提供する(@Transactional
のような宣言的なAPIではない) - JDBCのセーブポイント機能を提供する
使い方は次の節で述べます。
Domaのローカルトランザクション
動くコードはgetting-startedにありますが、ここでは重要な部分を抜粋して示します。
public class Main {
public static void main(String[] args) {
var config =
SimpleConfig.builder("jdbc:h2:mem:tutorial;DB_CLOSE_DELAY=-1", "sa", null)
.jdbcLogger(new Slf4jJdbcLogger())
.build();
var tm = config.getTransactionManager();
// setup database
var appDao = new AppDaoImpl(config);
tm.required(appDao::create);
// read and update
tm.required(
() -> {
var repository = new EmployeeRepository(config);
var employee = repository.selectById(1);
employee.age += 1;
repository.update(employee);
});
}
}
Domaのローカルトランザクションを使う場合、SimpleConfig
を使ってConfig
を生成することをお勧めします。SimpleConfig
を使えば、ローカルトランザクションを利用するための設定が自動で行われます。
config.getTransactionManager()
で取得できるtm
はLocalTransactionManager
のインスタンスです。tm
のrequired
メソッドにトランザクション内で扱いたい処理をラムダ式で渡すことでトランザクションを実行できます。
required
メソッドはトランザクションがまだ開始されていなかったら開始するメソッドで、他に常に新規にトランザクションを開始するrequiresNew
メソッドやトランザクションを一旦停止するnotSupported
メソッドなどがあります。これらのメソッドはネストして使えます。
ラムダ式から例外をスローするかsetRollbackOnly
メソッドを呼び出すかするとトランザクションはロールバックされます。それ以外ではコミットされます。
おわりに
Domaでトランザクションを利用するポイントを紹介しました。
Domaを使っていてトランザクションがうまく動いていないなと思ったら、この記事をはじめリンク先の記事やサンプルも参考にしてもらえればと思います。