はじめに
Spring を使っているとよく見かける
@Transactional。
「つけるだけでトランザクション管理ができるらしい」
「でも、どうやって動いているのかはよくわからない」
そんな気持ちになる方も多いと思います。
この記事では、@Transactional のしくみを
やさしく・実務で役立つ形 で整理していきます。
まずはコードを見て、そこから少しずつ理解していきましょう。
まずはコードを確認
@Service
public class UserService {
@Transactional
public void createUser() {
// ユーザー登録
// メール送信
// ログ記録
}
}このコードでは、createUser() の処理全体が
ひとつのトランザクションとして扱われます。
コードのしくみを解説
@Transactional とは
一言でいうと、
「このメソッドをトランザクションとして扱ってください」
という宣言です。
Spring が裏側で
- トランザクションを開始
- メソッドが正常終了したらコミット
- 例外が出たらロールバック
を自動で行ってくれます。
どうやって動いているのか
実は @Transactional は
AOP(アスペクト指向プログラミング)
によって実現されています。
Spring は @Transactional が付いたメソッドを呼ぶときに、
その前後に「トランザクション開始」「コミット/ロールバック」を
そっと挟み込んでくれます。
@Transactional の基本ルール
正常終了 → コミット
メソッドが例外なく終わると、DB の変更が確定します。
例外発生 → ロールバック
RuntimeException または Error が発生するとロールバックされます。
※ CheckedException はデフォルトではロールバックされません。
メソッドの外側から呼ばれたときだけ有効
@Transactional は プロキシ(代理オブジェクト) を使って動くため、
同じクラス内のメソッド呼び出しでは動きません。
例:
public void methodA() {
methodB(); // methodB に @Transactional が付いていても無効
}あわせて知っておきたいポイント
伝播(Propagation)
@Transactional には「トランザクションをどう扱うか」の設定があります。
代表的なものは以下の通りです。
- REQUIRED(デフォルト)
既存のトランザクションがあれば参加、なければ新規作成 - REQUIRES_NEW
常に新しいトランザクションを開始 - MANDATORY
既存のトランザクションが必須
実務では REQUIRED と REQUIRES_NEW をよく使います。
隔離レベル(Isolation)
同時実行時のデータ整合性をどう保つかの設定です。
- READ_COMMITTED
- REPEATABLE_READ
- SERIALIZABLE
などがありますが、基本はデフォルトで問題ありません。
readOnly = true
読み取り専用のトランザクションにできます。
パフォーマンスが向上することがあります。
使うときに気をつけたいこと
同じクラス内の呼び出しでは動かない
AOP の仕組み上、プロキシを経由しないため無効になります。
private メソッドには効かない
プロキシが呼び出せないため、@Transactional は適用されません。
チェック例外ではロールバックされない
必要なら
@Transactional(rollbackFor = Exception.class)のように指定します。
トランザクションの範囲を広げすぎない
大きすぎるトランザクションはロック競合の原因になります。
まとめ
@Transactional は、
「メソッドをトランザクションとして扱うための宣言」 です。
- 正常終了 → コミット
- 例外発生 → ロールバック
- AOP によって前後に処理が挟まれる
- 同じクラス内の呼び出しでは無効
難しく聞こえますが、
「Spring がメソッドの前後にトランザクション処理を挟んでくれる」
と理解できれば十分です。

@Transactional は便利ですが、仕組みを知ると
「なぜ動かないのか」「なぜロールバックされないのか」
といった疑問が一気に解消されます。
あなたの開発が、今日より少しだけ楽になりますように。

メソッドの前後でそっと守ってくれるなんて…Spring さん、やさしいね。

コメント