前書き: 最近、Spring トランザクションの 7 つの伝播メカニズムの説明について、インターネットで多くの記事を読みました。実際のコードと組み合わせて説明されているものはほとんどありません。Xiaobi の場合、無味乾燥なテキストの説明はやや抽象的で、具体的な説明はありません次に、春の出来事の各伝播メカニズムを理論と実践を通じて分析して、結局のところ、真実をテストするには実践のみであることを誰でも簡単に覚えられるようにします。コードのすべての単語と行はブロガーによって手入力されています。
目次
2.2.1、@Transactional アノテーションなし
2.2.2、 @Transactional アノテーションを追加
3.2.1、@Transactional アノテーションなし
3.2.2、 @Transactional アノテーションを追加
5.2.1、@Transactional アノテーションなし
5.2.2、 @Transactional アノテーションを追加
6.2.1、@Transactional アノテーションなし
6.2.2. @Transactional アノテーションの追加
7.2.1、@Transactional アノテーションなし
7.2.2. @Transactional アノテーションの追加
1. 必須 (デフォルト)
1.1. 基本概念
公式説明: 現在のトランザクションがある場合はトランザクションに参加し、現在のトランザクションがない場合は新しいトランザクションを作成します。
メソッド A と B の両方に @Transactional アノテーションが付けられている場合、デフォルトは REQUIRED の伝播動作になります。次に、メソッド A がメソッド B を呼び出すと、デフォルトで同じ接続が使用されるため、トランザクションを共有します。これは 1 つのトランザクションで実行するのと同じです。
1.2. コードの詳細説明
たとえば、ユーザー情報を挿入した後、すぐにロール情報が挿入されますが、最後に約数を 0 にすることはできないという例外を手動で記述しました。キー コードは次のとおりです。
UserService キーコード:
@Transactional(rollbackFor = Exception.class)
public void insertUser(){
User user = new User();
user.setId(UUID.randomUUID().toString());
user.setUsername("张三");
user.setPassword("123456");
userMapper.insert(user);
roleService.insertRole();
int a = 1/0;
}
役割サービスのキーコード:
@Transactional(rollbackFor = Exception.class)
public void insertRole(){
Role role = new Role();
role.setId(UUID.randomUUID().toString());
role.setName("管理员");
roleMapper.insert(role);
}
操作の結果は次のようになります。
プログラムではjava.lang.ArithmeticException:/by zeroの例外がスローされますが、トランザクションはロールバックされました。
2. サポート
2.1. 基本概念
公式説明: 現在トランザクションがある場合はトランザクションに参加し、トランザクションがない場合は非トランザクションで実行を継続します。
メソッド A にトランザクションがなく (@Transactional アノテーションなし)、メソッド B が SUPPORTS 伝播動作で構成されている場合、メソッド B も非トランザクション方式で実行されます。
メソッド A にトランザクション (@Transactional アノテーションが付けられている) があり、メソッド B が SUPPORTS 伝播動作で構成されている場合、メソッド B は自身のトランザクションを一時停止し、実行のためにメソッド A のトランザクションに追加します。
2.2. コードの詳細説明
全体的なコードロジックは変更されません。
2.2.1、@Transactional アノテーションなし
insertUser メソッドに @Transactional アノテーションを追加しないでください。
UserService キーコード:
public void insertUser(){
User user = new User();
user.setId(UUID.randomUUID().toString());
user.setUsername("张三");
user.setPassword("123456");
userMapper.insert(user);
roleService.insertRole();
int a = 1/0;
}
役割サービスのキーコード:
@Transactional(rollbackFor = Exception.class,propagation = Propagation.SUPPORTS)
public void insertRole(){
Role role = new Role();
role.setId(UUID.randomUUID().toString());
role.setName("管理员");
roleMapper.insert(role);
}
操作の結果は次のようになります。
プログラムではjava.lang.ArithmeticException: / by zeroの例外がスローされますが、insertUser メソッドがトランザクションを構成していないため、2 つのデータがデータベースに正常に格納されていることがわかります。 , そのため、insertRole メソッドも非トランザクション的な方法で実行されます。
2.2.2、 @Transactional アノテーションを追加
@Transactional アノテーションを insertUser メソッドに追加するだけです。
UserService キーコード:
@Transactional(rollbackFor = Exception.class)
public void insertUser(){
User user = new User();
user.setId(UUID.randomUUID().toString());
user.setUsername("张三");
user.setPassword("123456");
userMapper.insert(user);
roleService.insertRole();
int a = 1/0;
}
RoleService コードは移動しません。
操作の結果は次のようになります。
プログラムはjava.lang.ArithmeticException: / by zeroの例外をスローしますが、2 つのデータはロールバックされています。これは、insertRole メソッドが SUPPORTS 伝播動作を構成しているためで、insertRole メソッドは自身のトランザクションを一時停止し、 insertUser メソッドのトランザクションに追加して実行します。
3. 必須
3.1. 基本概念
公式説明: 現在トランザクションが存在する場合はトランザクションに参加し、現在トランザクションが存在しない場合は例外がスローされます。
メソッド A にトランザクションがなく (@Transactional アノテーションなし)、メソッド B が MANDATORY 伝播動作で構成されている場合、メソッド B は例外をスローします。
メソッド A にトランザクションがあり (@Transactional アノテーションを追加)、メソッド B が MANDATORY 伝播動作で構成されている場合、メソッド B は実行のために既存のトランザクションに追加されます。
3.2. コードの詳細説明
全体的なコードロジックは変更されません。
3.2.1、@Transactional アノテーションなし
insertUser メソッドに @Transactional アノテーションを追加しないでください。
UserService キーコード:
public void insertUser(){
User user = new User();
user.setId(UUID.randomUUID().toString());
user.setUsername("张三");
user.setPassword("123456");
userMapper.insert(user);
roleService.insertRole();
int a = 1/0;
}
役割サービスのキーコード:
@Transactional(rollbackFor = Exception.class,propagation = Propagation.MANDATORY)
public void insertRole(){
Role role = new Role();
role.setId(UUID.randomUUID().toString());
role.setName("管理员");
roleMapper.insert(role);
}
操作の結果は次のようになります。
プログラムはorg.springframework.transaction.IllegalTransactionStateException をスローします。伝播「必須」例外情報でマークされたトランザクションに既存のトランザクションが見つかりません。データベース側のユーザー情報は保存されますが、データベース側にトランザクションがないため、ロール情報は保存されません。 insertUser メソッド。この例外が発生し、データはデータベースに正常に保存されます。
3.2.2、 @Transactional アノテーションを追加
@Transactional アノテーションを insertUser メソッドに追加するだけです。
UserService キーコード:
@Transactional(rollbackFor = Exception.class)
public void insertUser(){
User user = new User();
user.setId(UUID.randomUUID().toString());
user.setUsername("张三");
user.setPassword("123456");
userMapper.insert(user);
roleService.insertRole();
int a = 1/0;
}
RoleService コードは移動しません。
操作の結果は次のようになります。
プログラムはjava.lang.ArithmeticException: / by zero例外情報をスローしますが、2 つのデータはロールバックされていますが、上記のorg.springframework.transaction.IllegalTransactionStateException: 伝播「必須」とマークされたトランザクションに対する既存のトランザクションが見つかりません。例外情報が失われているため、このトランザクションの伝播メカニズムにはアクティブなトランザクションの存在が必要です。
4. REQUIRES_NEW
4.1. 基本概念
公式説明: 新しいトランザクションを作成し、現在のトランザクションがある場合は、現在のトランザクションを一時停止します。
メソッド A と B の両方にトランザクションがあるが、B が REQUIRES_NEW で構成されている場合、B は新しいトランザクションを開始し、A のトランザクションを一時停止します。B のトランザクションが終了するまで待ってから、A のトランザクションを再開します。
4.2. コードの詳細説明
全体的なコードロジックは変更されません。
UserService キーコード:
@Transactional(rollbackFor = Exception.class)
public void insertUser(){
User user = new User();
user.setId(UUID.randomUUID().toString());
user.setUsername("张三");
user.setPassword("123456");
userMapper.insert(user);
roleService.insertRole();
int a = 1/0;
}
役割サービスのキーコード:
@Transactional(rollbackFor = Exception.class,propagation = Propagation.REQUIRES_NEW)
public void insertRole(){
Role role = new Role();
role.setId(UUID.randomUUID().toString());
role.setName("管理员");
roleMapper.insert(role);
}
操作の結果は次のようになります。
プログラムはjava.lang.ArithmeticException: / by zero例外情報をスローしますが、Role 情報は正常に挿入されます。これは、insertUser メソッドと insertRole メソッドが同じトランザクションを共有していないためであり、共通のデータベース接続が確立されているとも言えます。同じではありません。
5、サポートされていません
5.1. 基本概念
公式説明: 非トランザクション モードで実行し、現在のトランザクションがある場合は、現在のトランザクションを一時停止します。
メソッド A にトランザクションがなく (@Transactional アノテーションなし)、メソッド B が NOT_SUPPORTED 伝播動作で構成されている場合、メソッド B も非トランザクション方式で実行されます。
メソッド A (@Transactional アノテーションが付けられている) にトランザクションがあり、メソッド B が NOT_SUPPORTED 伝播動作で構成されている場合、メソッド B は自身のトランザクションを一時停止し、非トランザクション方式でメソッド A のトランザクションに参加して実行します。
5.2. コードの詳細説明
全体的なコードロジックは変更されません。
5.2.1、@Transactional アノテーションなし
insertUser メソッドに @Transactional アノテーションを追加しないでください。
UserService キーコード:
public void insertUser(){
User user = new User();
user.setId(UUID.randomUUID().toString());
user.setUsername("张三");
user.setPassword("123456");
userMapper.insert(user);
roleService.insertRole();
int a = 1/0;
}
役割サービスのキーコード:
@Transactional(rollbackFor = Exception.class,propagation = Propagation.NOT_SUPPORTED)
public void insertRole(){
Role role = new Role();
role.setId(UUID.randomUUID().toString());
role.setName("管理员");
roleMapper.insert(role);
}
操作の結果は次のようになります。
プログラムではjava.lang.ArithmeticException: / by zeroの例外がスローされますが、2 つのデータは正常に格納されていることがわかります。insertUser メソッドはトランザクションを構成しませんが、insertRole メソッドはトランザクションを構成します。 NOT_SUPPORTED 伝播動作の場合、insertRole メソッドも非トランザクション方式で実行されます。
5.2.2、 @Transactional アノテーションを追加
@Transactional アノテーションを insertUser メソッドに追加するだけです。
UserService キーコード:
@Transactional(rollbackFor = Exception.class)
public void insertUser(){
User user = new User();
user.setId(UUID.randomUUID().toString());
user.setUsername("张三");
user.setPassword("123456");
userMapper.insert(user);
roleService.insertRole();
int a = 1/0;
}
RoleService コードは移動しません。
操作の結果は次のようになります。
java.lang.ArithmeticException: / by zeroの例外がプログラムでスローされますが、insertUser メソッドがトランザクションを構成するのに対し、insertRole メソッドはNOT_SUPPORTED 伝播動作の場合、 insertRole メソッドは自身のトランザクションを一時停止し、insertUser メソッドに追加されたトランザクション内で非トランザクション方式で実行します。
6、決してしない
6.1. 基本概念
公式説明: 非トランザクション モードで実行し、現在のトランザクションがある場合は例外をスローします。
メソッド A にトランザクションがなく (@Transactional アノテーションなし)、メソッド B が NEVER 伝播動作で構成されている場合、メソッド B は非トランザクションで通常どおり実行されます。
メソッド A (@Transactional アノテーションが付けられている) にトランザクションがあり、メソッド B が NEVER 伝播動作で構成されている場合、メソッド B は例外をスローします。
6.2. コードの詳細説明
全体的なコードロジックは変更されません。
6.2.1、@Transactional アノテーションなし
insertUser メソッドに @Transactional アノテーションを追加しないでください。
UserService キーコード:
public void insertUser(){
User user = new User();
user.setId(UUID.randomUUID().toString());
user.setUsername("张三");
user.setPassword("123456");
userMapper.insert(user);
roleService.insertRole();
int a = 1/0;
}
役割サービスのキーコード:
@Transactional(rollbackFor = Exception.class,propagation = Propagation.NEVER)
public void insertRole(){
Role role = new Role();
role.setId(UUID.randomUUID().toString());
role.setName("管理员");
roleMapper.insert(role);
}
操作の結果は次のようになります。
プログラムではjava.lang.ArithmeticException: / by zeroの例外がスローされますが、insertUser メソッドではトランザクションが設定されていないため、insertRole メソッドでは 2 つのデータが正常に格納されていることがわかります。メソッドが NOT_SUPPORTED 伝播動作を構成すると、insertRole メソッドは非トランザクション方式で実行されます。
6.2.2. @Transactional アノテーションの追加
@Transactional アノテーションを insertUser メソッドに追加するだけです。
UserService キーコード:
@Transactional(rollbackFor = Exception.class)
public void insertUser(){
User user = new User();
user.setId(UUID.randomUUID().toString());
user.setUsername("张三");
user.setPassword("123456");
userMapper.insert(user);
roleService.insertRole();
int a = 1/0;
}
RoleService コードは移動しません。
操作の結果は次のようになります。
プログラムは、org.springframework.transaction.IllegalTransactionStateException: 伝播 'never' 例外情報がマークされたトランザクションで既存のトランザクションが見つかりましたが 、同時に 2 つのデータが正常に格納されていません。insertUser メソッドはトランザクションを構成し、insertRole メソッドは NEVER 伝播動作を構成するため、insertRole メソッドは例外メッセージをスローします。
7. ネストされた
7.1. 基本概念
公式説明: 現在のトランザクションが存在する場合は、現在のトランザクションのネストされたトランザクションとして実行するトランザクションを作成します。現在のトランザクションが存在しない場合、値は REQUIRED と同等です。
メソッド A にトランザクションがなく (@Transactional アノテーションなし)、メソッド B が NESTED 伝播動作で構成されている場合、メソッド B は新しいネストされたトランザクションの実行を開始します。
メソッド A (@Transactional アノテーションが付けられている) にトランザクションがあり、メソッド B が NESTED 伝播動作で構成されている場合、メソッド B はネストされたトランザクションで実行されます。
7.2. コードの詳細説明
全体的なコードロジックは変更されません。
7.2.1、@Transactional アノテーションなし
insertUser メソッドに @Transactional アノテーションを追加しないでください。
UserService キーコード:
public void insertUser(){
User user = new User();
user.setId(UUID.randomUUID().toString());
user.setUsername("张三");
user.setPassword("123456");
userMapper.insert(user);
roleService.insertRole();
int a = 1/0;
}
役割サービスのキーコード:
@Transactional(rollbackFor = Exception.class,propagation = Propagation.NESTED)
public void insertRole(){
Role role = new Role();
role.setId(UUID.randomUUID().toString());
role.setName("管理员");
roleMapper.insert(role);
}
操作の結果は次のようになります。
プログラムではjava.lang.ArithmeticException: / by zeroの例外がスローされますが、2 つのデータが正常に格納されていることがわかります。insertUser メソッドはトランザクションを構成せず、insertRole メソッドは NESTED 伝播動作を構成するため、insertRole メソッドは新しいネストされたトランザクションの実行を開始します。
7.2.2. @Transactional アノテーションの追加
@Transactional アノテーションを insertUser メソッドに追加するだけです。
UserService キーコード:
@Transactional(rollbackFor = Exception.class)
public void insertUser(){
User user = new User();
user.setId(UUID.randomUUID().toString());
user.setUsername("张三");
user.setPassword("123456");
userMapper.insert(user);
roleService.insertRole();
int a = 1/0;
}
RoleService コードは移動しません。
操作の結果は次のようになります。
プログラムではjava.lang.ArithmeticException:/by zeroの例外がスローされますが、2 つのデータはロールバックされていることが明確にわかります。これは、insertUser メソッドがトランザクションを構成し、insertRole メソッドが NESTED 伝播動作を構成すると、insertRole メソッドがネストされたトランザクションで実行されるためです。
8. まとめ
以上、Springトランザクションの伝播メカニズムを7つまとめてみましたが、いずれもブロガーが作成したもので、各トランザクションの伝播メカニズムを理論と実践を通してわかりやすく解説しており、誰でも理解できるようになっています。 . 質問、コメント欄での議論を歓迎します。