【Java・SpringBoot】@Transactionの設定まとめ

ホーム画面からユーザー一覧画面に遷移し、ユーザーの詳細を表示するアプリケーションを作成して、Spring JDBCの使い方について学びます⭐️
前回、前々回では宣言的/明示的トランザクションを学びました。
今回は**宣言的トランザクション(@Transaction)の設定**についてのまとめです^^
構成は前回/前々回の記事を参考にしてください

⭐️前回/前々回の記事
[Java・SpringBoot】宣言的トランザクション処理（SpringBootアプリケーション実践編20）](https://qiita.com/suema0331/items/2dee56f9de5b82a2ad40)
[【Java・SpringBoot】明示的トランザクション処理（SpringBootアプリケーション実践編21）](https://qiita.com/suema0331/items/20dfb63bef0a39ef79a2)

#@Transactionアノテーションの設定
| 属性 | 説明 |
|:-:|:-:|
|  value | 複数のトランザクションマネージャーを使用する場合、利用するトランザクションマネージャーのQualifierを指定する。<br>デフォルトでは省略可能(**transactionManager**も同じ)  |
|  propagation  | トランザクションの**伝播**レベルを指定  |
| isolation  | トランザクションの**分離**レベルを指定  |
|  timeout | トランザクションの**タイムアウト時間**（秒）を指定。<br>デフォルトは-1（使用するデータベースの仕様や設定に依存）
| readOnly  | トランザクションの**読取専用フラグ**を指定。<br>デフォルトはfalse（読取専用ではない）  |
| rollbackFor  | トランザクションの**ロールバック対象とする例外クラスのリスト**を指定。<br>デフォルトはRuntimeException（非検査例外）がロールバック対象。  |
| rollbackForClassName  | トランザクションの**ロールバック対象とする例外クラス名**のリストを指定。<br>デフォルトは空（指定なし）  |
| noRollbackFor  | トランザクションの**コミット対象とする例外クラスのリスト**を指定。<br>デフォルトは空（指定なし）  |
| noRollbackForClassName  |  トランザクションの**コミット対象とする例外クラス名**のリストを指定。<br>デフォルトは空（指定なし） |

#トランザクションの独立性（分離性）
* トランザクションを**複数同時に実行しても、正常な処理をしなければならない**こと
* 複数ユーザーがアプリケーションを使う場合、トランザクションは複数存在する
* →同じデータを参照する際には注意が必要！
    * ex: トランザクションA、Bが同時に口座の情報を読み取り、**同時に更新した場合に、データ不整合**になってしまう
    * トランザクションAが終了するまで、トランザクションBは待機しないといけない
* **Springの分離レベル**で独立性のレベルを指定



#トランザクション分離レベル
* トランザクションの分離レベルは、**isolation属性**に以下の値を指定

| 分離レベル | 説明 |
|:-:|:-:|
| DEFAULT  | 利用するデータベースのデフォルトの分離レベルを利用  |
| READ_UNCOMMITTED  | 他のトランザクションが、**まだコミットしていないデータを読み出せる**。<br>変更データが**ロールバックされた場合、次のトランザクションでは無効な行データが検索**される  |
|READ_COMMITTED   | 他のトランザクションが**コミットしていないデータは読み出せない**  |
|REPEATABLE_READ   | トランザクション内で、**複数回データを読み込んだ場合、他のトランザクションが途中でデータを変更しても、同じ値**が読み込まれる |
| SERIALIZABLE  |  トランザクションを**順番に処理** |

 
#独立性における代表的な問題
* **ダーティリード**
    * 他のトランザクションが**変更したが、まだコミットしていない**データを読み取ってしまい、**誤ったデータを読み取ってしまう**
* **ノンリピータブルリード**
    * トランザクションの中で、何回も同じデータを読み取るときに、**他のトランザクションがデータを更新してしまうと、途中から違う値を読み取ってしまう**
* **ファントムリード**
    * トランザクションの中で、何回も同じデータを読み取ると、**他のトランザクションが新しくデータを追加すると途中から処理対象のレコードが増える**

###分離レベルが問題を解決できるかどうか
| 分離レベル | ダーティリード | ノンリピータブルリード | ファントムリード |
|:-:|:-:|:-:|:-:|
| READ_UNCOMMITTED  | ×  | ×  | ×  |
| READ_COMMITTED  | 〇  | ×  |  × |
|REPEATABLE_READ   |  〇 | 〇  | ×  |
|  SERIALIZABLE | 〇  | 〇  |  〇 |

#トランザクションの伝播レベル
* **トランザクションを新たに作成し、開始するかどうか**の設定
* 特に、**サービスクラスから別のサービスクラスを呼び出す**場合、トランザクションを開始するのか、既存トランザクションに参加するのかを設定することができる
    * トランザクションを直接呼ぶときは、**トランザクション開始する・例外を投げる・作成しない**のどれに当てはまるか、
    * 間接的に呼ぶときは、**参加する・開始する・例外を投げる・作成しない**、のどれに当てはまるか、を検討する


| 伝播レベル | 説明 |
|:-:|:-:|
| REQUIRED  | デフォルト設定。トランザクションが**存在しない場合、新規にトランザクションを開始**。すでに**存在する場合はそのトランザクションを利用**  |
| QUIRES_NEW  | **必ず新規のトランザクション**を作成  |
| MANDATORY  | すでに**トランザクションが存在することを前提**にし、トランザクションが**存在しない場合、例外発生**。<br>すでに存在する場合は、そのトランザクションを利用  |
|  NEVER | トランザクションを使用しない。<br>すでに**トランザクションが存在する場合は例外が発生**  |
| NOT_SUPPORTED  | **トランザクションを使用しない**。<br>すでにトランザクションが**存在する場合はそのトランザクションを一時停止し、トランザクションを使用せずに処理を実行後、停止していたトランザクションを再開**  |
| SUPPORTS  | トランザクションが**存在しない場合、トランザクション作成しない**。<br>既に存在する場合は、そのトランザクションを利用  |
| NESTED  | **ネストしたトランザクションを作成**。<br>トランザクションが**存在しない場合、新規にトランザクションを開始し、すでに存在する場合はそのトランザクションを利用するが、その部分だけネストしたトランザクションのように処理**   |