1. はじめに
Spring Bootで統合テストを書く際、@Transactional
を使ってテスト後にデータをロールバックするのは一般的かと思います。しかし、複雑なトランザクション制御が必要なケースではTransactionTemplate
が便利だったので本記事では、TransactionTemplate
の実践的な使い方と、@Transactional
との使い分けについてまとめようと思います。
2. @Transactionalによる統合テストの基本
Spring Bootでは、テストクラスやテストメソッドに@Transactional
を付けることで、テスト実行後に自動的にトランザクションがロールバックされます。
@SpringBootTest
@Transactional
class UserServiceTest {
@Autowired
private UserRepository userRepository;
@Test
void testUserCreation() {
userRepository.save(new User("Taro"));
assertEquals(1, userRepository.count());
}
}
この方法はシンプルで便利ですが、以下のような制約があります:
- テストメソッド全体が1つのトランザクションになる
- 明示的なコミットやロールバックができない
- 非同期処理や別スレッドでのトランザクション制御が難しい
3. TransactionTemplateとは?
TransactionTemplate
は、Springのトランザクション管理をプログラム的に制御できるユーティリティです。明示的にトランザクションの境界を定義できるため、テスト内で細かく制御したい場合に有効です。
@Autowired
private TransactionTemplate transactionTemplate;
@Test
void testWithTransactionTemplate() {
transactionTemplate.execute(status -> {
userRepository.save(new User("Hanako"));
return null;
});
assertEquals(1, userRepository.count());
}
このコードでは、userRepository.save(...) の処理のみをトランザクションで囲んでいます。execute(...) メソッドの中で定義された処理ブロックが、トランザクションの境界となります。
4. 実践例:@Transactionalでは困難なケース
ケース1:テスト中に明示的なロールバックを行いたい
@Test
void testRollbackManually() {
transactionTemplate.execute(status -> {
userRepository.save(new User("Jiro"));
status.setRollbackOnly(); // 明示的にロールバック
return null;
});
assertEquals(0, userRepository.count());
}
ケース2:複数のトランザクションを分けてテストしたい
@Test
void testMultipleTransactions() {
transactionTemplate.execute(status -> {
userRepository.save(new User("A"));
return null;
});
transactionTemplate.execute(status -> {
userRepository.save(new User("B"));
return null;
});
assertEquals(2, userRepository.count());
}
このテストでは、TransactionTemplate#execute() を2回呼び出すことで、2つの独立したトランザクションを順に実行しています。それぞれのexecute()ブロックは、個別のトランザクション境界を持ち、互いに影響を与えません。
@Transactionalを使った場合、テストメソッド全体が1つのトランザクションに包まれるため、途中でトランザクションを明示的に分けることはできません。このようなケースでは、TransactionTemplateのようなプログラム的トランザクション制御が有効です。
5. @Transactionalとの使い分けのポイント
シーン | @Transactional | TransactionTemplate |
---|---|---|
単純なロールバック付きテスト | ✅ | ✅ |
明示的なロールバック制御 | ❌ | ✅ |
複数トランザクションの分離 | ❌ | ✅ |
非同期処理との組み合わせ | ❌ | ✅ |
テストの簡潔さ | ✅ | △(やや冗長) |
6. まとめ
@Transactional
はシンプルで便利ですが、複雑なトランザクション制御が必要な統合テストではTransactionTemplate
が非常に有効です。使い分けることで、より堅牢で柔軟なテスト設計が可能になります。
本記事が何かのお役に立てば幸いです!
7. 参考