トランザクション
Doma はローカルトランザクションをサポートしています。このドキュメントでは、ローカルトランザクションの設定方法と使用方法について説明します。
グローバルトランザクションを使用する場合は、JTA (Java Transaction API) をサポートするフレームワークまたはアプリケーションサーバーを使用してください。
設定の定義 も参照してください。
設定
ローカル トランザクションを使用するには、次の条件が必要です。
Config実装のgetDataSourceメソッドからLocalTransactionDataSourceを返します。コンストラクターで
LocalTransactionDataSourceを使用してLocalTransactionManagerを作成しますこの
LocalTransactionManagerを使用してデータベースアクセスを制御します
LocalTransactionManager を生成・取得する方法はいくつかありますが、最も簡単な方法は Config 実装クラスのコンストラクタ内で生成し、Config 実装クラスをシングルトンにすることです。
以下に例を示します。
public class DbConfig implements Config {
private static final DbConfig CONFIG = new DbConfig();
private final Dialect dialect;
private final LocalTransactionDataSource dataSource;
private final TransactionManager transactionManager;
private DbConfig() {
dialect = new H2Dialect();
dataSource = new LocalTransactionDataSource(
"jdbc:h2:mem:tutorial;DB_CLOSE_DELAY=-1", "sa", null);
transactionManager = new LocalTransactionManager(
dataSource.getLocalTransaction(getJdbcLogger()));
}
@Override
public Dialect getDialect() {
return dialect;
}
@Override
public DataSource getDataSource() {
return dataSource;
}
@Override
public TransactionManager getTransactionManager() {
return transactionManager;
}
public static DbConfig singleton() {
return CONFIG;
}
}
使用法
次の例ではこのDAOインターフェースを使用します。
@Dao
public interface EmployeeDao {
@Sql("select /*%expand*/* from employee where id = /*id*/0")
@Select
Employee selectById(Integer id);
@Update
int update(Employee employee);
@Delete
int delete(Employee employee);
}
トランザクションの開始と管理
次の TransactionManager のメソッドのいずれかを使用してトランザクションを開始できます。
required- 利用可能な既存のトランザクションを使用するか、存在しない場合は新しいトランザクションを作成しますrequiresNew- 常に新しいトランザクションを作成し、既存のトランザクションを中断しますnotSupported- トランザクションなしで実行され、既存のトランザクションを一時停止します
ラムダ式を使用して、トランザクションで実行するコードを定義します。
void doSomething() {
TransactionManager tm = DbConfig.singleton().getTransactionManager();
EmployeeDao dao = new EmployeeDaoImpl(DbConfig.singleton());
tm.required(() -> {
Employee employee = dao.selectById(1);
employee.setName("hoge");
employee.setJobType(JobType.PRESIDENT);
dao.update(employee);
});
}
トランザクションはラムダ式が正常に完了した場合、自動的にコミットされます。ラムダ式が例外をスローした場合、トランザクションは自動的にロールバックされます。
明示的なロールバック
例外をスローする以外に、setRollbackOnly メソッドを使用してトランザクションを明示的にロールバックすることもできます。
void doSomething() {
TransactionManager tm = DbConfig.singleton().getTransactionManager();
EmployeeDao dao = new EmployeeDaoImpl(DbConfig.singleton());
tm.required(() -> {
Employee employee = dao.selectById(1);
employee.setName("hoge");
employee.setJobType(JobType.PRESIDENT);
dao.update(employee);
// Mark as rollback
tm.setRollbackOnly();
});
}
セーブポイントの使用
セーブポイントを使用すると、トランザクションの特定の部分をロールバックしながら他の変更を維持できます。
void doSomething() {
TransactionManager tm = DbConfig.singleton().getTransactionManager();
EmployeeDao dao = new EmployeeDaoImpl(DbConfig.singleton());
tm.required(() -> {
// Search and update
Employee employee = dao.selectById(1);
employee.setName("hoge");
dao.update(employee);
// Create a savepoint
tm.setSavepoint("beforeDelete");
// Delete
dao.delete(employee);
// Rollback to the savepoint (cancel the deletion above)
tm.rollback("beforeDelete");
});
}