トランザクションの伝播

このセクションでは、Spring でのトランザクション伝播のセマンティクスについて説明します。このセクションは、トランザクション伝播の適切な導入ではないことに注意してください。むしろ、Spring でのトランザクション伝播に関するセマンティクスのいくつかを詳しく説明しています。

Spring 管理のトランザクションでは、物理トランザクションと論理トランザクションの違い、および伝播設定がこの違いにどのように適用されるかに注意してください。

PROPAGATION_REQUIRED を理解する

tx prop required

PROPAGATION_REQUIRED は、トランザクションがまだ存在しない場合は現在のスコープに対してローカルに、またはより大きなスコープに対して定義された既存の「外部」トランザクションに参加して、物理トランザクションを実施します。これは、同じスレッド内の一般的なコールスタック配置(たとえば、基礎となるすべてのリソースがサービスレベルトランザクションに参加する必要がある複数のリポジトリメソッドに委譲するサービスファサード)のデフォルトです。

デフォルトでは、参加トランザクションは外部スコープの特性に参加し、ローカルの分離レベル、タイムアウト値、読み取り専用フラグ(存在する場合)を静かに無視します。分離レベルが異なる既存のトランザクションに参加するときに分離レベルの宣言を拒否する場合は、トランザクションマネージャーで validateExistingTransactions フラグを true に切り替えることを検討してください。この非寛容なモードは、読み取り専用の不一致(つまり、読み取り専用の外部スコープに参加しようとする内部読み取り / 書き込みトランザクション)も拒否します。

伝播設定が PROPAGATION_REQUIRED の場合、設定が適用されるメソッドごとに論理トランザクションスコープが作成されます。このような各論理トランザクションスコープは、ロールバックのみのステータスを個別に決定できます。外側のトランザクションスコープは、内側のトランザクションスコープから論理的に独立しています。標準の PROPAGATION_REQUIRED 動作の場合、これらのスコープはすべて同じ物理トランザクションにマップされます。そのため、内部トランザクションスコープに設定されたロールバック専用マーカーは、外部トランザクションが実際にコミットする機会に影響します。

ただし、内部トランザクションスコープがロールバック専用マーカーを設定する場合、外部トランザクションはロールバック自体を決定していないため、ロールバック(内部トランザクションスコープによってサイレントにトリガーされる)は予期されていません。その時点で、対応する UnexpectedRollbackException がスローされます。これは予想される動作であるため、トランザクションの呼び出し元は、実際にはコミットが実行されていないときにコミットが実行されたと誤解することはありません。そのため、(外部の呼び出し元が認識していない)内部のトランザクションがトランザクションをロールバック専用としてサイレントにマークした場合、外部の呼び出し元はコミットを呼び出します。外側の呼び出し元は、UnexpectedRollbackException を受信して、代わりにロールバックが実行されたことを明確に示す必要があります。

PROPAGATION_REQUIRES_NEW を理解する

tx prop requires new

 PROPAGATION_REQUIRED とは対照的に、PROPAGATION_REQUIRES_NEW は、影響を受けるトランザクションスコープごとに独立した物理トランザクションを常に使用し、外部スコープの既存のトランザクションには関与しません。このような配置では、基になるリソーストランザクションは異なり、独立したコミットまたはロールバックが可能です。外側のトランザクションは、内側のトランザクションのロールバックステータスの影響を受けず、内側のトランザクションのロックは完了直後に解放されます。このような独立した内部トランザクションは、独自の分離レベル、タイムアウト、読み取り専用設定も宣言でき、外部トランザクションの特性を継承しません。

外部トランザクションにアタッチされたリソースは、内部トランザクションが新しいデータベース接続などの独自のリソースを取得している間、そこにバインドされたままになります。これにより、接続プールが枯渇し、複数のスレッドがアクティブな外部トランザクションを持ち、内部トランザクションの新しい接続の取得を待機し、プールがそのような内部接続を渡すことができなくなった場合、潜在的にデッドロックが発生する可能性があります。接続プールのサイズが適切で、同時スレッド数を少なくとも 1 超えない限り、PROPAGATION_REQUIRES_NEW を使用しないでください。

PROPAGATION_NESTED を理解する

PROPAGATION_NESTED は、ロールバック可能な複数のセーブポイントを持つ単一の物理トランザクションを使用します。このような部分的なロールバックにより、内部トランザクションスコープはそのスコープのロールバックをトリガーできます。一部の操作がロールバックされても、外部トランザクションは物理トランザクションを続行できます。通常、この設定は JDBC セーブポイントにマップされるため、JDBC リソーストランザクションでのみ機能します。Spring の DataSourceTransactionManager (Javadoc) を参照してください。