| この記事の要点 |
|
@Transactional とは
@Transactional は、Spring Framework で DB を更新する際のトランザクションを管理するアノテーションです。付けたメソッドの開始時にトランザクションを開始し、正常に終わればコミット、例外が投げられればロールバックします。commit() や rollback() を自分で書かずに、「このメソッドの中の DB 操作はすべて成功するか、すべて取り消されるか」を保証できます。
クラスもしくはメソッド単位で付与することができます。クラスに付けるとそのクラスの public メソッドすべてに適用され、クラスとメソッドの両方に付与した場合はメソッドのアノテーションの設定が優先されます。
Spring Boot では、spring-boot-starter-data-jpa や spring-boot-starter-jdbc を依存に加えるとトランザクション管理が自動で有効になるため、@EnableTransactionManagement を自分で書く必要は通常ありません。
基本的な使い方
一般的には、業務ロジックをまとめる Service クラスのメソッドに付けます。
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@Service
public class TransferService {
private final AccountRepository accountRepository;
public TransferService(AccountRepository accountRepository) {
this.accountRepository = accountRepository;
}
@Transactional
public void transfer(Long fromId, Long toId, long amount) {
Account from = accountRepository.findById(fromId).orElseThrow();
Account to = accountRepository.findById(toId).orElseThrow();
from.withdraw(amount); // 残高不足なら RuntimeException
to.deposit(amount);
// 例外が出れば、両方の変更がロールバックされる
}
}
次は JpaRepository で、更新系のクエリメソッドに @Transactional を使用した例です。@Modifying 付きの更新クエリはトランザクション内で実行する必要があります。
@Repository
public interface TestRepository extends JpaRepository<TestEntity, String> {
@Transactional
@Modifying
@Query("UPDATE TestEntity te SET te.colA = 1 WHERE te.id = :id")
Integer updateTest(@Param("id") String id);
}
なお、save() や findById() など Spring Data JPA が標準で提供するメソッドには、最初からトランザクション設定が付いています。
主なオプション
| 属性 | 既定値 | 意味 |
|---|---|---|
| propagation | REQUIRED | 既にトランザクションがあるときの振る舞い(下表) |
| isolation | DEFAULT | 分離レベル。DEFAULT は DB の既定に従う(MySQL InnoDB なら REPEATABLE READ) |
| readOnly | false | 読み取り専用のヒント。JPA ではフラッシュを省くなどの最適化が効く |
| timeout | -1(無制限) | タイムアウト秒数 |
| rollbackFor | なし | 追加でロールバック対象にする例外クラス |
| noRollbackFor | なし | ロールバックしない例外クラス |
| transactionManager(value) | 既定のもの | 複数 DB を使うときに使うトランザクションマネージャを指定 |
propagation(伝播)の種類
| 値 | 既存トランザクションがある場合 | ない場合 |
|---|---|---|
| REQUIRED | それに参加する | 新しく開始する |
| REQUIRES_NEW | 既存を一時停止して、別の新しいトランザクションを開始する | 新しく開始する |
| NESTED | セーブポイントを作って入れ子で実行する | 新しく開始する |
| SUPPORTS | 参加する | トランザクションなしで実行する |
| MANDATORY | 参加する | 例外を投げる |
| NOT_SUPPORTED | 既存を一時停止してトランザクションなしで実行する | トランザクションなしで実行する |
| NEVER | 例外を投げる | トランザクションなしで実行する |
REQUIRES_NEW は「本処理が失敗しても操作ログだけは必ず残したい」といった場面で使います。
ロールバックされる例外・されない例外
既定では、RuntimeException(非チェック例外)と Error ではロールバックし、チェック例外(IOException など)ではコミットします。チェック例外でもロールバックしたい場合は次のように指定します。
@Transactional(rollbackFor = Exception.class)
public void importCsv(Path file) throws IOException {
// IOException が出てもロールバックされる
}
@Transactional(readOnly = true)
public List<User> findActiveUsers() {
return userRepository.findByActiveTrue();
}
Spring Framework 6.2 以降では、@EnableTransactionManagement(rollbackOn = RollbackOn.ALL_EXCEPTIONS) でアプリ全体の既定を「すべての例外でロールバック」に変えることもできます。
効かないときの落とし穴
- 同じクラス内のメソッドから呼んでいる: @Transactional は Spring が作るプロキシを経由した呼び出しにだけ効く。
this.save()のような自己呼び出しではプロキシを通らないため、トランザクションが開始されない。別の Bean に切り出すのが基本の対処 - Spring 管理外のオブジェクト:
newで作ったインスタンスのメソッドには効かない - 例外を握りつぶしている: メソッド内で catch して外に投げないと、正常終了とみなされてコミットされる
- private メソッド: プロキシから呼べないため効かない。Spring 6 以降は、クラスベースのプロキシなら protected やパッケージプライベートのメソッドにも適用される
- アノテーションの取り違え:
jakarta.transaction.Transactionalも Spring で動くが、readOnly・isolation・timeout などの属性はorg.springframework.transaction.annotation.Transactionalにしかない。import を確認する - 別スレッドでの処理: トランザクションはスレッドに紐づくため、
@Asyncや自前のスレッドで実行した処理は呼び出し元のトランザクションに含まれない
確認方法
トランザクションが開始・コミット・ロールバックされているかは、ログで確認するのが確実です。application.properties に次を追加します。
logging.level.org.springframework.transaction=DEBUG
logging.level.org.springframework.orm.jpa.JpaTransactionManager=DEBUG
メソッド呼び出し時に「Creating new transaction with name [...]」、終了時に「Committing」や「Rolling back」といったログが出れば、正しく適用されています。コード内で確認したい場合は TransactionSynchronizationManager.isActualTransactionActive() が true を返すかを見ます。
関連
- DB トランザクション完全ガイド(SQL BEGIN/COMMIT / Laravel / Spring / 分離レベル / デッドロック)
- SQL トランザクション制御 完全ガイド(BEGIN/COMMIT/ROLLBACK/SAVEPOINT/ACID/分離レベル)
- SQL SAVEPOINT の使い方 - 部分ロールバック・ネストトランザクション完全ガイド
- 【Spring】DB接続設定から値の取得まで(JdbcTemplate編)
- Hibernateとは|JavaのORMライブラリとJPA参照実装の基礎
子ページはありません
人気ページ
- 1 Eclipseで「サーバーに追加または除去できるリソースがありません。」の原因と対処法
- 2 tomcat の起動 / 停止ログと catalina.log・catalina.out の違い
- 3 JavaScript で base URL を取得する方法|window.location.origin
- 4 YouTube Data API v3 エラー一覧|403・400・404 の原因と対処
- 5 Laravel エラー一覧|500/Blade/DB 接続/ルーティングの代表エラー
- 6 3Dグラフィックスのソフト一覧|Blender・Metasequoiaと用途別の選び方
- 7 Spring Frameworkのアノテーション一覧
- 8 【Spring】@Valueアノテーションとは
- 9 CATALINA_HOME の確認方法 (Linux / Mac)
- 10 【Spring】@Autowiredアノテーションとは
最近更新/作成されたページ
- Visual Studio「デザイナーを表示できません」エラーの原因と対処 2026-10-28 12:06:00
- SSH 認証に失敗しました。再試行してください の対処 2026-10-28 12:06:00
- SSH2 秘密鍵の読み込みに失敗しました の原因と対処 2026-10-28 12:06:00
- TeraTerm のよくあるエラーと対処法完全ガイド — Connection refused / 2026-10-28 12:06:00
- Visual Studio エラー一覧|コンパイルエラー・警告の確認方法と対処 2026-10-28 11:39:57
- Whitelabel Error Page の原因と消し方|Spring Boot のエラーページ 2026-10-28 11:39:57
- Eclipseで「サーバーに追加または除去できるリソースがありません。」の原因と対処法 2026-10-28 11:39:57
- SQL WHERE 句完全ガイド 2026-10-28 11:39:57
- SQL JOIN 完全ガイド (INNER/LEFT/RIGHT/FULL OUTER) 2026-10-28 11:39:57
- tomcat の起動 / 停止ログと catalina.log・catalina.out の違い 2026-10-28 10:24:23
- Tomcat の起動確認方法 5 つ|localhost:8080・ポート・プロセス・ログ 2026-10-28 10:24:23
- Oracle 19c COMMITの使い方: 暗黙コミット・自動確定・応答不明時の確認 2026-10-28 09:59:09
- Oracle 19c DELETE文|削除対象の確認・COMMIT前の判断・ROLLBACKの条件 2026-10-28 09:59:09
- Oracle 19c INSERT文|INSERT ALL・SELECT・RETURNINGとMERGEの使い分け 2026-10-28 09:59:09
- Oracle 19cのトランザクション制御|COMMIT・ROLLBACK・分離レベルと接続設定 2026-10-28 09:59:09