こんにちは。SpringBootの勉強シリーズです。
今回はSpringBootのアノテーション「@Transactional」の挙動を整理します。
なお、トランザクション分離レベルなどは触れません。トランザクションのシンプルな挙動の理解を目指します。
環境
- SpringBoot(バージョンは適当)
- Postgresql(バージョンは適当)
※たぶんバージョンとかDBに関係あることは書きません。
まずはじめに
あいかわらずSpringBootの勉強中です。
よく以下のような実装を見ます。今日はこの実装を紐解いていきます。
(実際のソースコードは10倍くらい複雑ですけど)
@Transactional
public void insertSample(String name, int point) {
sampleMapper.insertSample(name, point);
}
トランザクションとは
複数の処理をまとめた単位らしいです。
トランザクションの挙動
以下のような処理があります。
@Transactional
public void insertSample(String name, int point) {
sampleMapper.insertSample(name, point); // ①DBへの登録
doSomething(); // ②ここでエラーが発生するかもしれない
}
正常終了時
@Transactionalを付与されたメソッドが完了時に、DBに対してコミットして、更新を実際に反映します。
異常終了時
①で登録後に、②でエラーが発生するとします。
この場合に、トランザクションとして、エラーを検知してロールバックして、①のINSERTがなかったことになります。
以下のように、トランザクション内でエラーが起こった場合に、ロールバックが発生します。
何が嬉しいのか
以下のような場合にメリットがあります。
- 処理取り消し(ロールバック)の個別実装が不要
- 複数テーブルに跨った更新に対して、一貫性を担保できる
- Javaの領域で起こったエラーに対して、DBのロールバックをフレームワークに任せることができる
たとえば下記の図のように、2つのテーブルを更新する処理があるとします。この場合、片方のテーブルだけが更新されて、もう片方が更新されないという状況を防ぐことができます。トランザクションを使用することで、両方のテーブルの更新が成功するか、両方とも元の状態に戻るかのどちらかになります。
トランザクションの処理中のDBの状態は?
コミットされていなければ、DBに反映されません。
すなわち、処理中のトランザクションは、コミットされるまで他者からは反映を確認できません。
以下の例ですと、ユーザーBからは、ユーザーAの処理がコミットされるまでは、変更前の情報が参照されます。
ではどんな時でも、トランザクションにしておけば安心なのか
そういうわけではありません。トランザクション内での更新は、そのトランザクションがコミットされるまでレコードをロックするため、他からの更新が待機してしまいます。
これは以下のような状況で問題になる可能性があります:
- 大量のデータを更新する処理
- 外部APIを呼び出すなど、処理時間が長くなる可能性がある処理
- 複数のトランザクションが同じテーブルに対して更新を行う処理
特に注意が必要なのは、複数のトランザクションが異なる順序でテーブルを更新する場合です。
以下のような状況では、デッドロックが発生する可能性があります。
実際には、デッドロックが発生した場合、各DBMSによって検知してエラーとなります。そして場合によりますが、どちらかのトランザクションをエラーとし、どちらかを完了させます。
このような問題を防ぐためには、以下のようなことをします。
-
トランザクションの範囲は必要最小限にする
- 外部APIの呼び出しはトランザクションの外で行う
- 大量データの更新は適切な単位で分割する
-
テーブルの更新順序を統一する
- 複数のトランザクションで同じテーブルを更新する場合は、更新順序をアプリケーション側で揃える
- 例:テーブルA → テーブルB → テーブルC という順序を統一する
トランザクションは便利な機能ですが、適切な範囲で使用することが重要です。
必要以上に大きな範囲をトランザクションにすると、アプリケーションのパフォーマンスに影響を与える可能性があります。
まとめ
SpringBootにおいて、トランザクション(@Transactional)配下の処理が
- 成功した場合
- DBにも反映される
- 失敗した場合
- DBもロールバックする
という挙動でACID特性のA(Atomicity)が担保されます。
実際には
- フレームワークの挙動(アノテーションのその他のオプション)
- DBの挙動
- トランザクション分離レベル
などなど、理解すべきことが多いですが、まずはシンプルに挙動をまとめてみました。
初学者の方、実際に案件で使用している方に、勉強も兼ねてご参考になれば幸いです。
以上です。また何かまとめます。