Spring 事务传播机制
一、demo目录介绍
所有demo代码位置:gitee.com/old_yogurt/…
所有的demo测试从 测试类出发,命名规则都是传播行为的名字。
每一个传播行为,都定义了A method()方法,和B method()方法;如:上图中绿色框住的 mandatory 传播行为。
建议:查看文章的同时下载项目代码,方便测试;同时:通过观察,事务ID,事务状态,事务名,数据库操作结果,会有比较深刻的理解。
二、Spring 事务对于异常的捕获
从 ExceptionTransactionalTest
测试出发!!!
- 事务只会捕获RuntimeException。对于Exception不进行事务回滚。
- 1、抛出RuntimeException
- 2、如果想要抛出 Exception,或者自定义异常,需要同时在事务声明中加上
@Transactional(rollbackFor = Exception.class)
2.1 抛出 RuntimeException运行时异常
/**
* 1、抛出 RuntimeException运行时异常
*/
@Test
public void runtimeExceptionTest(){
Integer bId = 3;
try {
bnTransactionalService.runtimeExceptionTest(bId);
} catch (RuntimeException e) {
System.out.println("############ 捕获B method 抛出的异常RuntimeException ############");
e.printStackTrace();
}
}
@Transactional
public void runtimeExceptionTest(Integer id) throws RuntimeException{
bnMapper.deleteB(id);
// 或者不用主动抛出异常,直接
// int a = 2/0,抛出的异常就是运行时异常
throw new RuntimeException();
}
测试结果:事务可以处理RuntimeException()异常,再抛出异常的同时,方法中对于 数据库的delete操作会回滚。
2.2 抛出Exception,并声明异常
@Test
public void exceptionTest(){
Integer bId = 3;
try {
bnTransactionalService.exceptionTest(bId);
} catch (Exception e) {
System.out.println("############ 捕获B method 抛出的Exception异常 ############");
e.printStackTrace();
}
}
@Transactional(rollbackFor = Exception.class)
public void exceptionTest(Integer id) throws Exception {
bnMapper.deleteB(id);
throw new Exception();
}
测试结果:事务可以处理Exception()异常,再抛出异常的同时,方法中对于 数据库的delete操作会回滚。
2.3 抛出Exception,但不声明异常
@Test
public void exceptionTest_3(){
Integer bId = 3;
try {
bnTransactionalService.exceptionTest_2(bId);
} catch (Exception e) {
System.out.println("############ 捕获B method 抛出的Exception异常 ############");
e.printStackTrace();
}
}
@Transactional
public void exceptionTest_2(Integer id) throws Exception {
bnMapper.deleteB(id);
throw new Exception();
}
测试结果:事务不可以处理Exception()异常,会抛出异常,但是数据库的操作却不会回滚。
三、REQUIRED
从 RequiredTransactionalTest
测试出发!!!
- REQUIRED:
- 表示当前方法必须在一个具有事务的上下文中运行,如果有加入当前事务,如果没有开启一个新的事务。
- 1、A method() 不开启事务, B method() 事务传播特性:REQUIRED
- 那么 B method 开启事务。
- 2、A method() 开启事务, B method() 事务传播行为:REQUIRED
- 那么B method()会加入到 A的事务中!
- 3、A method() 开启事务, B method() 事务传播行为:REQUIRED
- 3.1 如果 B method() 抛出异常,B method()和A method()都会回滚。
- 3.2 如果 A method 捕获了 B method()抛出的异常,则会出现异常Transaction rolled back because it has been marked as rollback-only。
- 抛出的一次也说明了 rollback-only 只能回滚,所以 A,B都回滚。
3.1 A 不开启事务,B 事务传播特性:REQUIRED
@Test
public void requiredTest_1(){
A a = new A();
a.setName("娜娜");
a.setSex("女");
Integer bId = 4;
anRequiredTransactionalService.anRequiredTest_1(a,bId);
}
public void anRequiredTest_1(A a,Integer bId){
// 可以查看当前方法所在线程是否有事务开启。
boolean anTransactionActive = TransactionSynchronizationManager.isActualTransactionActive();
String currentTransactionName = TransactionSynchronizationManager.getCurrentTransactionName();
System.out.println("A method 返回当前是否有实际事务处于活动状态 : "+ anTransactionActive);
System.out.println("A method 当前事务name : "+ currentTransactionName);
anMapper.insertSelective(a);
bnRequiredTransactionalService.bnRequiredTest_1(bId);
}
@Transactional(propagation = Propagation.REQUIRED)
public void bnRequiredTest_1(Integer id){
boolean bnTransactionActive = TransactionSynchronizationManager.isActualTransactionActive();
String currentTransactionName = TransactionSynchronizationManager.getCurrentTransactionName();
System.out.println("B method 返回当前是否有实际事务处于活动状态 : " +bnTransactionActive);
System.out.println("B method 当前事务name : "+ currentTransactionName);
bnMapper.deleteB(id);
}
测试结果:
可以看到下面打印的信息: A method 返回当前是否有实际事务处于活动状态 : false A method 当前事务name : null B method 返回当前是否有实际事务处于活动状态 : true B method 当前事务name : com.transactional.service.impl.required.BnRequiredTransactionalServiceImpl.bnRequiredTest_1
从打印结果中我们可以看到,B开启了事务。
3.2 A 开启事务,B 事务传播特性:REQUIRED
@Test
public void requiredTest_2(){
A a = new A();
a.setName("Tom");
a.setSex("man");
Integer bId = 4;
anRequiredTransactionalService.anRequiredTest_2(a,bId);
}
@Transactional
public void anRequiredTest_2(A a,Integer bId){
// 可以查看当前方法所在线程是否有事务开启。
boolean anTransactionActive = TransactionSynchronizationManager.isActualTransactionActive();
String currentTransactionName = TransactionSynchronizationManager.getCurrentTransactionName();
System.out.println("A method 返回当前是否有实际事务处于活动状态 : "+ anTransactionActive);
System.out.println("A method 当前事务name : "+ currentTransactionName);
anMapper.insertSelective(a);
bnRequiredTransactionalService.bnRequiredTest_2(bId);
}
@Transactional(propagation = Propagation.REQUIRED)
public void bnRequiredTest_2(Integer id){
boolean bnTransactionActive = TransactionSynchronizationManager.isActualTransactionActive();
String currentTransactionName = TransactionSynchronizationManager.getCurrentTransactionName();
System.out.println("B method 返回当前是否有实际事务处于活动状态 : " +bnTransactionActive);
System.out.println("B method 当前事务name : "+ currentTransactionName);
bnMapper.deleteB(id);
}
测试结果:
从打印信息 可以看到,A,B在同一事务中: A method 返回当前是否有实际事务处于活动状态 : true A method 当前事务name : com.transactional.service.impl.required.AnRequiredTransactionalServiceImpl.anRequiredTest_2 B method 返回当前是否有实际事务处于活动状态 : true B method 当前事务name : com.transactional.service.impl.required.AnRequiredTransactionalServiceImpl.anRequiredTest_2
从打印结果可以看到:由于A开启了事务,说明有当前事务存在,那么,B 事务传播特性:REQUIRED会使得 B加入到当前事务中,所示,A,B两个事务的名称是一样的。
3.3 A 开启事务,B 事务传播特性:REQUIRED且抛出异常
@Test
public void anRequiredTest_4(){
A a = new A();
a.setName("Tom");
a.setSex("man");
Integer bId = 5;
anRequiredTransactionalService.anRequiredTest_4(a,bId);
}
@Transactional
public void anRequiredTest_4(A a,Integer bId){
// 可以查看当前方法所在线程是否有事务开启。
System.out.println("A method 返回当前是否有实际事务处于活动状态 : "+ TransactionSynchronizationManager.isActualTransactionActive());
System.out.println("A method 当前事务name : "+ TransactionSynchronizationManager.getCurrentTransactionName());
anMapper.insertSelective(a);
bnRequiredTransactionalService.bnRequiredTest_4(bId);
}
@Transactional(propagation = Propagation.REQUIRED)
public void bnRequiredTest_4(Integer id){
System.out.println("B method 返回当前是否有实际事务处于活动状态 : " +TransactionSynchronizationManager.isActualTransactionActive());
System.out.println("B method 当前事务name : "+ TransactionSynchronizationManager.getCurrentTransactionName());
bnMapper.deleteB(id);
//抛出异常
throw new RuntimeException();
}
测试结果:A,B在同一个事务中,异常由当前事务捕获,两个都会回滚。查看数据库:a表没有插入数据,b表没有删除数据。
3.4 A 开启事务,B 事务传播特性:REQUIRED且抛出异常,由A捕获B的异常
@Test
public void requiredTest_5(){
A a = new A();
a.setName("Tom");
a.setSex("man");
Integer bId = 4;
anRequiredTransactionalService.anRequiredTest_5(a,bId);
}
@Transactional
@Override
public void anRequiredTest_5(A a, Integer bId) {
// 可以查看当前方法所在线程是否有事务开启。
System.out.println("A method 返回当前是否有实际事务处于活动状态 : "+ TransactionSynchronizationManager.isActualTransactionActive());
System.out.println("A method 当前事务name : "+ TransactionSynchronizationManager.getCurrentTransactionName());
anMapper.insertSelective(a);
// 这里A method()只要开启事务,B method()没有事务或者事务传播行为是REQUIRED,B method()都会在事务中
// 这里bnRequiredTest_5() 抛出异常
try {
bnRequiredTransactionalService.bnRequiredTest_5(bId);
}catch (RuntimeException e){
e.printStackTrace();
}
}
@Transactional(propagation = Propagation.REQUIRED)
public void bnRequiredTest_5(Integer id){
System.out.println("B method 返回当前是否有实际事务处于活动状态 : " +TransactionSynchronizationManager.isActualTransactionActive());
System.out.println("B method 当前事务name : "+ TransactionSynchronizationManager.getCurrentTransactionName());
bnMapper.deleteB(id);
throw new RuntimeException();
}
运行结果:A,B都会回滚,并且抛出 Transaction rolled back because it has been marked as rollback-only。
四、SUPPORTS
从 SupportsTransactionTest
测试出发!!!
- SUPPORTS:
- 1、 A 不开启事务,B 事务传播行为:SUPPORTS
- 不会以事务方式运行
- 2、A 开启事务,B 事务传播行为:SUPPORTS
- B 会在A开启的事务中运行
- 3、A 开启事务;A抛出异常,B 事务传播行为:SUPPORTS
- A method,B method 都会回滚
- 4、A 开启事务;B 事务传播行为SUPPORTS,抛出异常,A捕获B的异常
- A method()和B method()都会被回滚,并抛出 UnexpectedRollbackException: Transaction silently rolled back because it has been marked as rollback-only
- 5、A 开启事务;B 事务传播行为SUPPORTS,抛出异常,A不捕获B的异常
- A method()和B method()都会被回滚
- 1、 A 不开启事务,B 事务传播行为:SUPPORTS
4.1 A 不开启事务,B 事务传播行为:SUPPORTS
@Test
public void supportTest_1(){
A a = new A();
a.setName("小明");
a.setSex("男");
Integer bId = 5;
anSupportsTransactionalService.anSupportsTest_1(a,bId);
}
public void anSupportsTest_1(A a, Integer bId){
System.out.println("A method 返回当前是否有实际事务处于活动状态 : "+ TransactionSynchronizationManager.isActualTransactionActive());
System.out.println("A method 当前事务name : "+ TransactionSynchronizationManager.getCurrentTransactionName());
anMapper.insertSelective(a);
bnSupportsTransactionalService.bnSupportsTest_1(bId);
}
@Transactional(propagation = Propagation.SUPPORTS)
public void bnSupportsTest_1(Integer id){
System.out.println("B method 返回当前是否有实际事务处于活动状态 : " +TransactionSynchronizationManager.isActualTransactionActive());
System.out.println("B method 当前事务name : "+ TransactionSynchronizationManager.getCurrentTransactionName());
bnMapper.deleteB(id);
}
运行结果:
打印结果: A method 返回当前是否有实际事务处于活动状态 : false A method 当前事务name : null B method 返回当前是否有实际事务处于活动状态 : false B method 当前事务name : com.transactional.service.impl.supports.BnSupportsTransactionalServiceImpl.bnSupportsTest_1
从打印结果可以看出:B method 不会以事务方式运行!
4.2 A 开启事务,B 事务传播行为:SUPPORTS
@Test
public void supportTest_2(){
A a = new A();
a.setName("小明");
a.setSex("男");
Integer bId = 5;
anSupportsTransactionalService.anSupportsTest_2(a,bId);
}
@Transactional
public void anSupportsTest_2(A a, Integer bId){
System.out.println("A method 返回当前是否有实际事务处于活动状态 : "+ TransactionSynchronizationManager.isActualTransactionActive());
System.out.println("A method 当前事务name : "+ TransactionSynchronizationManager.getCurrentTransactionName());
anMapper.insertSelective(a);
bnSupportsTransactionalService.bnSupportsTest_1(bId);
}
@Transactional(propagation = Propagation.SUPPORTS)
public void bnSupportsTest_1(Integer id){
System.out.println("B method 返回当前是否有实际事务处于活动状态 : " +TransactionSynchronizationManager.isActualTransactionActive());
System.out.println("B method 当前事务name : "+ TransactionSynchronizationManager.getCurrentTransactionName());
bnMapper.deleteB(id);
}
测试结果:
打印结果: A method 返回当前是否有实际事务处于活动状态 : true A method 当前事务name : com.transactional.service.impl.supports.AnSupportsTransactionalServiceImpl.anSupportsTest_2 B method 返回当前是否有实际事务处于活动状态 : true B method 当前事务name : com.transactional.service.impl.supports.AnSupportsTransactionalServiceImpl.anSupportsTest_2
从打印结果看到: B,A在同一事务中运行
4.3 A 开启事务;A 抛出异常,B 事务传播行为:SUPPORTS
@Test
public void supportTest_3(){
A a = new A();
a.setName("小明");
a.setSex("男");
Integer bId = 5;
anSupportsTransactionalService.anSupportsTest_3(a,bId);
}
@Transactional
public void anSupportsTest_3(A a, Integer bId){
System.out.println("A method 返回当前是否有实际事务处于活动状态 : "+ TransactionSynchronizationManager.isActualTransactionActive());
System.out.println("A method 当前事务name : "+ TransactionSynchronizationManager.getCurrentTransactionName());
anMapper.insertSelective(a);
bnSupportsTransactionalService.bnSupportsTest_1(bId);
// 抛出运行时异常
int f = 2/0;
}
@Transactional(propagation = Propagation.SUPPORTS)
public void bnSupportsTest_1(Integer id){
System.out.println("B method 返回当前是否有实际事务处于活动状态 : " +TransactionSynchronizationManager.isActualTransactionActive());
System.out.println("B method 当前事务name : "+ TransactionSynchronizationManager.getCurrentTransactionName());
bnMapper.deleteB(id);
}
运行结果:
首先 B 是在A 的事务中运行的;然后A抛出异常,那么 A method,B method 都会回滚。 可以查看数据库, A表没有插入对用数据,B表没有删除对应数据。
4.4 A 开启事务;B 事务传播行为SUPPORTS,抛出异常,A捕获B的异常
@Test
public void supportTest_4(){
A a = new A();
a.setName("小明");
a.setSex("男");
Integer bId = 5;
anSupportsTransactionalService.anSupportsTest_4(a,bId);
}
@Transactional
public void anSupportsTest_4(A a, Integer bId){
System.out.println("A method 返回当前是否有实际事务处于活动状态 : "+ TransactionSynchronizationManager.isActualTransactionActive());
System.out.println("A method 当前事务name : "+ TransactionSynchronizationManager.getCurrentTransactionName());
anMapper.insertSelective(a);
try {
bnSupportsTransactionalService.bnSupportsTest_2(bId);
}catch (RuntimeException e){
// 注意,这里异常是RuntimeException时的
// 如果想要自定义异常去捕获处理,那么就要继承RuntimeException类
e.printStackTrace();
}
}
@Transactional(propagation = Propagation.SUPPORTS)
public void bnSupportsTest_2(Integer id){
System.out.println("B method 返回当前是否有实际事务处于活动状态 : " +TransactionSynchronizationManager.isActualTransactionActive());
System.out.println("B method 当前事务name : "+ TransactionSynchronizationManager.getCurrentTransactionName());
bnMapper.deleteB(id);
// method抛出运行时异常
int f = 2/0;
}
运行结果:A method()和B method()都会被回滚,并抛出 UnexpectedRollbackException: Transaction silently rolled back because it has been marked as rollback-only
4.5 A 开启事务;B 事务传播行为SUPPORTS,抛出异常,A不捕获B的异常
@Test
public void supportTest_5(){
A a = new A();
a.setName("小明");
a.setSex("男");
Integer bId = 5;
anSupportsTransactionalService.anSupportsTest_5(a,bId);
}
@Transactional
@Override
public void anSupportsTest_5(A a, Integer bId) {
System.out.println("A method 返回当前是否有实际事务处于活动状态 : "+ TransactionSynchronizationManager.isActualTransactionActive());
System.out.println("A method 当前事务name : "+ TransactionSynchronizationManager.getCurrentTransactionName());
anMapper.insertSelective(a);
bnSupportsTransactionalService.bnSupportsTest_2(bId);
}
@Transactional(propagation = Propagation.SUPPORTS)
public void bnSupportsTest_2(Integer id){
System.out.println("B method 返回当前是否有实际事务处于活动状态 : " +TransactionSynchronizationManager.isActualTransactionActive());
System.out.println("B method 当前事务name : "+ TransactionSynchronizationManager.getCurrentTransactionName());
bnMapper.deleteB(id);
// method抛出运行时异常
int f = 2/0;
}
运行结果:A method()和B method()都会被回滚
五、MANDATORY
从 MandatoryTransactionalTest
测试出发!!!
- MANDATORY
- 1、A 没有事务,而B 事务传播特性定义为:MANDATORY
- 那么会抛出No existing transaction found for transaction marked with propagation 'mandatory';
- 而且需要注意的是:A Method()有数据库操作是正常执行的,不会回滚(因为本身就没有事务),B Method()也不会进行回滚;其实应该是B都没有执行,因为在调用B的时候,spring事务会检查到B的注解上面的的参数是 MANDATORY就会抛出相应异常)。
- 2、A 开启事务,B 事务传播行为:MANDATORY
- 由于A开启事务,B会加入到A开始的事务中运行
- 3、A 开启事务并抛出异常,B 事务传播行为:MANDATORY
- A method 和 B method()执行的操作被回滚。
- 4、A 开启事务,B 事务传播行为:MANDATORY,抛出异常,A不捕获B的异常
- A method 和 B method()执行的操作被回滚。
- 5、A 开启事务,B 事务传播行为:MANDATORY,抛出异常,A捕获B的异常
- A method 和 B method()执行的操作被回滚,并且抛出异常 Transaction rolled back because it has been marked as rollback-only
5.1 A 没有事务,而B 事务传播特性定义为:MANDATORY
@Test
public void mandatoryTest_1(){
A a = new A();
a.setName("赵武");
a.setSex("男");
Integer bId = 3;
anTransactionalService.mandatoryTest_1(a,bId);
}
public void mandatoryTest_1(A a,Integer bId){
System.out.println("A method 返回当前是否有实际事务处于活动状态 : "+ TransactionSynchronizationManager.isActualTransactionActive());
System.out.println("A method 当前事务name : "+ TransactionSynchronizationManager.getCurrentTransactionName());
anMapper.insertSelective(a);
System.out.println("A method 当前事务id : "+ TransactionalId.getTransactionalId());
bnTransactionalService.mandatoryTest_1(bId);
}
@Transactional(propagation = Propagation.MANDATORY)
public void mandatoryTest_1(Integer id){
System.out.println("B method 返回当前是否有实际事务处于活动状态 : " + TransactionSynchronizationManager.isActualTransactionActive());
System.out.println("B method 当前事务name : "+ TransactionSynchronizationManager.getCurrentTransactionName());
bnMapper.deleteB(id);
System.out.println("B method 当前事务id : "+ TransactionalId.getTransactionalId());
}
运行结果:
抛出 No existing transaction found for transaction marked with propagation 'mandatory';
而且需要注意的是:A Method()有数据库操作是正常执行的,不会回滚(因为本身就没有事务),B Method()也不会进行回滚,其实应该是B都没有执行,因为在调用B的时候,spring事务会检查到B的注解上面的的参数是 MANDATORY就会抛出相应异常)。
数据库结果:a表正常插入,b表没有删除数据。
5.2 A 开启事务,B 事务传播行为:MANDATORY
@Test
public void mandatoryTest_2(){
A a = new A();
a.setName("小红");
a.setSex("女");
Integer bId = 3;
anTransactionalService.mandatoryTest_2(a,bId);
}
@Transactional
@Override
public void mandatoryTest_2(A a, Integer bId) {
// A method()执行了,B method()也执行了
anMapper.insertSelective(a);
bnTransactionalService.mandatoryTest_1(bId);
// 在A中抛出异常
throw new RuntimeException();
}
@Transactional(propagation = Propagation.MANDATORY)
public void mandatoryTest_1(Integer id){
System.out.println("B method 返回当前是否有实际事务处于活动状态 : " + TransactionSynchronizationManager.isActualTransactionActive());
System.out.println("B method 当前事务name : "+ TransactionSynchronizationManager.getCurrentTransactionName());
bnMapper.deleteB(id);
System.out.println("B method 当前事务id : "+ TransactionalId.getTransactionalId());
}
运行结果:
A method 返回当前是否有实际事务处于活动状态 : true A method 当前事务name : com.transactional.service.impl.mandatory.AnMandatoryTransactionalServiceImpl.mandatoryTest_2 A method 当前事务id : 30630 B method 返回当前是否有实际事务处于活动状态 : true B method 当前事务name : com.transactional.service.impl.mandatory.AnMandatoryTransactionalServiceImpl.mandatoryTest_2 B method 当前事务id : 30630
可以看到, 事务id一致,A,B处于同一事务中。
5.3 A 开启事务并抛出异常,B 事务传播行为:MANDATORY
@Test
public void mandatoryTest_3(){
A a = new A();
a.setName("小红");
a.setSex("女");
Integer bId = 3;
anTransactionalService.mandatoryTest_3(a,bId);
}
@Transactional
public void mandatoryTest_3(A a,Integer bId) {
System.out.println("A method 返回当前是否有实际事务处于活动状态 : "+ TransactionSynchronizationManager.isActualTransactionActive());
System.out.println("A method 当前事务name : "+ TransactionSynchronizationManager.getCurrentTransactionName());
anMapper.insertSelective(a);
System.out.println("A method 当前事务id : "+ TransactionalId.getTransactionalId());
bnTransactionalService.mandatoryTest_1(bId);
// 在A中抛出异常
throw new RuntimeException();
}
@Transactional(propagation = Propagation.MANDATORY)
public void mandatoryTest_1(Integer id){
System.out.println("B method 返回当前是否有实际事务处于活动状态 : " + TransactionSynchronizationManager.isActualTransactionActive());
System.out.println("B method 当前事务name : "+ TransactionSynchronizationManager.getCurrentTransactionName());
bnMapper.deleteB(id);
System.out.println("B method 当前事务id : "+ TransactionalId.getTransactionalId());
}
运行结果:
A method 和 B method()执行的操作被回滚。
数据库结果:a表没有插入数据,b表没有删除数据
5.4 A 开启事务,B 事务传播行为:MANDATORY,抛出异常,A不捕获B的异常
@Test
public void mandatoryTest_4(){
A a = new A();
a.setName("李四");
a.setSex("男");
Integer bId = 3;
anTransactionalService.mandatoryTest_4(a,bId);
}
@Transactional
@Override
public void mandatoryTest_4(A a, Integer bId) {
System.out.println("A method 返回当前是否有实际事务处于活动状态 : "+ TransactionSynchronizationManager.isActualTransactionActive());
System.out.println("A method 当前事务name : "+ TransactionSynchronizationManager.getCurrentTransactionName());
anMapper.insertSelective(a);
System.out.println("A method 当前事务id : "+ TransactionalId.getTransactionalId());
bnTransactionalService.mandatoryTest_2(bId);
}
@Transactional(propagation = Propagation.MANDATORY)
public void mandatoryTest_2(Integer id){
System.out.println("B method 返回当前是否有实际事务处于活动状态 : " + TransactionSynchronizationManager.isActualTransactionActive());
System.out.println("B method 当前事务name : "+ TransactionSynchronizationManager.getCurrentTransactionName());
bnMapper.deleteB(id);
System.out.println("B method 当前事务id : "+ TransactionalId.getTransactionalId());
// 抛出异常
int f = 2/0;
}
运行结果:
A method 和 B method()执行的操作被回滚。
数据库结果:a表没有insert数据,b表没有delete数据。
5.5 A 开启事务,B 事务传播行为:MANDATORY,抛出异常,A捕获B的异常
@Test
public void mandatoryTest_5(){
A a = new A();
a.setName("李四");
a.setSex("男");
Integer bId = 3;
anTransactionalService.mandatoryTest_5(a,bId);
}
@Transactional
@Override
public void mandatoryTest_5(A a, Integer bId) {
System.out.println("A method 返回当前是否有实际事务处于活动状态 : "+ TransactionSynchronizationManager.isActualTransactionActive());
System.out.println("A method 当前事务name : "+ TransactionSynchronizationManager.getCurrentTransactionName());
anMapper.insertSelective(a);
System.out.println("A method 当前事务id : "+ TransactionalId.getTransactionalId());
try {
bnTransactionalService.mandatoryTest_2(bId);
}catch (RuntimeException e){
System.out.println("########## A method 捕获 B method抛出的异常");
}
}
@Transactional(propagation = Propagation.MANDATORY)
@Override
public void mandatoryTest_2(Integer id){
System.out.println("B method 返回当前是否有实际事务处于活动状态 : " + TransactionSynchronizationManager.isActualTransactionActive());
System.out.println("B method 当前事务name : "+ TransactionSynchronizationManager.getCurrentTransactionName());
bnMapper.deleteB(id);
System.out.println("B method 当前事务id : "+ TransactionalId.getTransactionalId());
// 抛出异常
int f = 2/0;
}
运行结果:
A,B都会回滚。
并且抛出异常:Transaction rolled back because it has been marked as rollback-only
六、REQUIRES_NEW
从 RequiresNewTransactionTest
测试出发!!!
-
REQUIRES_NEW
-
表示当前方法需要运行在一个新的事务中,并且 上一个事务会被挂起。(点到
Propagation.REQUIRES_NEW
中 看源码注释说明) -
1、A 开启一个事务,B 事务传播行为:REQUIRES_NEW
- 结果: A 虽然开启事务,但是B 也开启了一个新的事务执行数据库操作。并且 上一个事务会被挂起,先执行当前事务操作。
-
2、A 开启一个事务,B 事务传播行为:REQUIRES_NEW,A 抛出异常
A.method()的事务被回滚,但B.method()事务不受影响 -> A method() insert操作被回滚,B method delete操作正常执行 ( 因为 A,B是在不同的事务中!!! )
-
3、A 开启一个事务,B 事务传播行为:REQUIRES_NEW并抛出异常
A B method()的事务都会被回滚 -> A method() insert操作被回滚,B method delete操作也会被回滚
-
4、A 开启一个事务,B 事务传播行为:REQUIRES_NEW并抛出异常,同时,A捕获B的异常
- A method() insert操作会正常执行,B method() delete操作会被回滚
-
6.1 A 开启一个事务,B 事务传播行为:REQUIRES_NEW
@Test
public void requiresNewTest_1(){
A a = new A();
a.setName("娜美");
a.setSex("女");
Integer bId = 16;
anRequiresNewTransactionalService.anRequiresNewTest_1(a,bId);
}
@Transactional
@Override
public void anRequiresNewTest_1(A a, Integer bId) {
System.out.println("A method 返回当前是否有实际事务处于活动状态 : "+ TransactionSynchronizationManager.isActualTransactionActive());
System.out.println("A method 当前事务name : "+ TransactionSynchronizationManager.getCurrentTransactionName());
anMapper.insertSelective(a);
System.out.println("A method 当前事务id : "+ TransactionalId.getTransactionalId());
bnRequiresNewTransactionalService.bnRequiresNewTest_1(bId);
}
@Transactional(propagation = Propagation.REQUIRES_NEW)
@Override
public void bnRequiresNewTest_1(Integer id) {
System.out.println("B method 返回当前是否有实际事务处于活动状态 : " + TransactionSynchronizationManager.isActualTransactionActive());
System.out.println("B method 当前事务name : "+ TransactionSynchronizationManager.getCurrentTransactionName());
bnMapper.deleteB(id);
//在这里打断点
System.out.println("B method 当前事务id : "+ TransactionalId.getTransactionalId());
}
看图打印结果:
测试的时候需要注意:
为了测试 B method开启新事务效果,需要在bnRequiresNewTest_1()打印 事务id列表的时候打个断点,走到断点在释放断点即可看到两个事务id返回。
运行结果:
从上面的打印结果可以看出, A method()虽然开启事务,但是B method()也开启了一个新的事务执行数据库操作;同时A 事务会挂起,先执行B 事务,B事务执行完之后,恢复A事务,A事务再执行
6.2 A 开启一个事务,B 事务传播行为:REQUIRES_NEW,A 抛出异常
@Test
public void requiresNewTest_2(){
A a = new A();
a.setName("娜美");
a.setSex("女");
Integer bId = 16;
anRequiresNewTransactionalService.anRequiresNewTest_2(a,bId);
}
@Transactional
@Override
public void anRequiresNewTest_2(A a, Integer bId) {
System.out.println("A method 返回当前是否有实际事务处于活动状态 : "+ TransactionSynchronizationManager.isActualTransactionActive());
System.out.println("A method 当前事务name : "+ TransactionSynchronizationManager.getCurrentTransactionName());
anMapper.insertSelective(a);
System.out.println("A method 当前事务id : "+ TransactionalId.getTransactionalId());
bnRequiresNewTransactionalService.bnRequiresNewTest_1(bId);
//抛出运行时异常
int f = 2/0;
}
@Transactional(propagation = Propagation.REQUIRES_NEW)
@Override
public void bnRequiresNewTest_1(Integer id) {
System.out.println("B method 返回当前是否有实际事务处于活动状态 : " + TransactionSynchronizationManager.isActualTransactionActive());
System.out.println("B method 当前事务name : "+ TransactionSynchronizationManager.getCurrentTransactionName());
bnMapper.deleteB(id);
System.out.println("B method 当前事务id : "+ TransactionalId.getTransactionalId());
}
运行结果:
A method 回滚,B method 正常执行 (这个其实也可以说明处在不同的事务中)
6.3 A 开启一个事务,B 事务传播行为:REQUIRES_NEW并抛出异常
@Test
public void requiresNewTest_3(){
A a = new A();
a.setName("娜美");
a.setSex("女");
Integer bId = 16;
anRequiresNewTransactionalService.anRequiresNewTest_3(a,bId);
}
@Transactional
@Override
public void anRequiresNewTest_3(A a, Integer bId) {
System.out.println("A method 返回当前是否有实际事务处于活动状态 : "+ TransactionSynchronizationManager.isActualTransactionActive());
System.out.println("A method 当前事务name : "+ TransactionSynchronizationManager.getCurrentTransactionName());
anMapper.insertSelective(a);
System.out.println("A method 当前事务id : "+ TransactionalId.getTransactionalId());
bnRequiresNewTransactionalService.bnRequiresNewTest_2(bId);
}
@Transactional(propagation = Propagation.REQUIRES_NEW)
@Override
public void bnRequiresNewTest_2(Integer id) {
System.out.println("B method 返回当前是否有实际事务处于活动状态 : " + TransactionSynchronizationManager.isActualTransactionActive());
System.out.println("B method 当前事务name : "+ TransactionSynchronizationManager.getCurrentTransactionName());
bnMapper.deleteB(id);
System.out.println("B method 当前事务id : "+ TransactionalId.getTransactionalId());
// 抛出异常
int f = 2/0;
}
运行结果:
A B method()的事务都会被回滚 -> A method() insert操作被回滚,B method delete操作也会被回滚
6.4 A 开启一个事务,B 事务传播行为:REQUIRES_NEW并抛出异常,同时,A捕获B的异常
@Test
public void requiresNewTest_4(){
A a = new A();
a.setName("娜美");
a.setSex("女");
Integer bId = 16;
anRequiresNewTransactionalService.anRequiresNewTest_4(a,bId);
}
@Transactional
@Override
public void anRequiresNewTest_4(A a, Integer bId) {
System.out.println("A method 返回当前是否有实际事务处于活动状态 : "+ TransactionSynchronizationManager.isActualTransactionActive());
System.out.println("A method 当前事务name : "+ TransactionSynchronizationManager.getCurrentTransactionName());
anMapper.insertSelective(a);
System.out.println("A method 当前事务id : "+ TransactionalId.getTransactionalId());
// A 捕获 B的异常
try {
bnRequiresNewTransactionalService.bnRequiresNewTest_2(bId);
}catch (RuntimeException e){
e.printStackTrace();
}
}
@Transactional(propagation = Propagation.REQUIRES_NEW)
@Override
public void bnRequiresNewTest_2(Integer id) {
System.out.println("B method 返回当前是否有实际事务处于活动状态 : " + TransactionSynchronizationManager.isActualTransactionActive());
System.out.println("B method 当前事务name : "+ TransactionSynchronizationManager.getCurrentTransactionName());
bnMapper.deleteB(id);
System.out.println("B method 当前事务id : "+ TransactionalId.getTransactionalId());
// 抛出异常
int f = 2/0;
}
运行结果:A method() insert操作会正常执行,B method() delete操作会被回滚
七、NOT_SUPPORTED
从 `NotSupportedTransactionTest 测试出发!!!
-
NOT_SUPPORTED
-
表示该方法不应该在一个事务中运行。如果有一个事务正在运行,他将在运行期被挂起,直到这个事务提交或者回滚才恢复执行。
-
1、 A 不开启事务,B 事务传播行为:NOT_SUPPORTED
-
结果:B 没有开启事务
-
2、 A method开启事务,B,事务传播行为:NOT_SUPPORTED
-
结果:A method 是在事务中运行的,并且事务是活动状态。
B method 则是等 A事务提交结束,以非事务的状态执行。
-
-
3、 A 开启事务并且A 抛出异常;B 事务传播行为:NOT_SUPPORTED
- 结果:这种属于,A method是在事务中,A 异常会回滚,B由于不在事务中执行,所以会被执行。 验证:表a没有插入数据库,表b中对应的数据被删除。
-
4、A 开启事务;B 事务传播行为:NOT_SUPPORTED;B 抛出异常,A不捕获
- 结果:A 的insert操作回滚,B 的delete的操作正常执行
-
5、A 开启事务;B 事务传播行为:NOT_SUPPORTED;B 抛出异常,A捕获
- A的insert操作正常执行,B的delete的操作也正常执行
-
7.1 A 不开启事务,B 事务传播行为:NOT_SUPPORTED
@Test
public void notSupportsTest_1(){
A a = new A();
a.setName("诺诺罗亚");
a.setSex("男");
Integer bId = 12;
anNotSupportedTransactionalService.anNoSupportedTest_1(a,bId);
}
@Override
public void anNoSupportedTest_1(A a, Integer bId) {
System.out.println("A method 返回当前是否有实际事务处于活动状态 : "+ TransactionSynchronizationManager.isActualTransactionActive());
System.out.println("A method 当前事务name : "+ TransactionSynchronizationManager.getCurrentTransactionName());
anMapper.insertSelective(a);
System.out.println("A method 当前事务id : "+ TransactionalId.getTransactionalId());
bnNotSupportedTransactionalService.bnNoSupportedTest_1(bId);
}
@Transactional(propagation = Propagation.NOT_SUPPORTED)
@Override
public void bnNoSupportedTest_1(Integer bId) {
System.out.println("B method 返回当前是否有实际事务处于活动状态 : " + TransactionSynchronizationManager.isActualTransactionActive());
System.out.println("B method 当前事务name : "+ TransactionSynchronizationManager.getCurrentTransactionName());
bnMapper.deleteB(bId);
System.out.println("B method 当前事务id : "+ TransactionalId.getTransactionalId());
}
运行结果:
打印记录: A method 返回当前是否有实际事务处于活动状态 : false A method 当前事务name : null B method 返回当前是否有实际事务处于活动状态 : false B method 当前事务name : com.transactional.service.impl.notsupported.BnNotSupportedTransactionalServiceImpl.bnNoSupportedTest_1
从打印记录可以看出 B method没有开启事务。
7.2 A method开启事务,B,事务传播行为:NOT_SUPPORTED
@Test
public void notSupportsTest_2(){
A a = new A();
a.setName("诺诺罗亚");
a.setSex("男");
Integer bId = 12;
anNotSupportedTransactionalService.anNoSupportedTest_2(a,bId);
}
@Transactional
@Override
public void anNoSupportedTest_2(A a, Integer bId) {
System.out.println("A method 返回当前是否有实际事务处于活动状态 : "+ TransactionSynchronizationManager.isActualTransactionActive());
System.out.println("A method 当前事务name : " + TransactionSynchronizationManager.getCurrentTransactionName());
anMapper.insertSelective(a);
System.out.println("A method 当前事务id : "+ TransactionalId.getTransactionalId());
bnNotSupportedTransactionalService.bnNoSupportedTest_1(bId);
}
@Transactional(propagation = Propagation.NOT_SUPPORTED)
@Override
public void bnNoSupportedTest_1(Integer bId) {
System.out.println("B method 返回当前是否有实际事务处于活动状态 : " + TransactionSynchronizationManager.isActualTransactionActive());
System.out.println("B method 当前事务name : "+ TransactionSynchronizationManager.getCurrentTransactionName());
bnMapper.deleteB(bId);
System.out.println("B method 当前事务id : "+ TransactionalId.getTransactionalId());
}
运行结果:
打印记录: A method 返回当前是否有实际事务处于活动状态 : true A method 当前事务name : com.transactional.service.impl.notsupported.AnNotSupportedTransactionalServiceImpl.anNoSupportedTest_2 A method 当前事务id : 30746 B method 返回当前是否有实际事务处于活动状态 : false B method 当前事务name : com.transactional.service.impl.notsupported.BnNotSupportedTransactionalServiceImpl.bnNoSupportedTest_1 B method 当前事务id : null
A method 是在事务中运行的,并且事务是活动状态。
B method 则是等 A事务提交结束,以非事务的状态执行。
7.3 A 开启事务并且A 抛出异常;B 事务传播行为:NOT_SUPPORTED
@Test
public void notSupportsTest_3(){
A a = new A();
a.setName("诺诺罗亚");
a.setSex("男");
Integer bId = 12;
anNotSupportedTransactionalService.anNoSupportedTest_3(a,bId);
}
@Transactional
@Override
public void anNoSupportedTest_3(A a, Integer bId) {
System.out.println("A method 返回当前是否有实际事务处于活动状态 : "+ TransactionSynchronizationManager.isActualTransactionActive());
System.out.println("A method 当前事务name : " + TransactionSynchronizationManager.getCurrentTransactionName());
anMapper.insertSelective(a);
System.out.println("A method 当前事务id : "+ TransactionalId.getTransactionalId());
bnNotSupportedTransactionalService.bnNoSupportedTest_1(bId);
int f = 2/0;
}
@Transactional(propagation = Propagation.NOT_SUPPORTED)
@Override
public void bnNoSupportedTest_1(Integer bId) {
System.out.println("B method 返回当前是否有实际事务处于活动状态 : " + TransactionSynchronizationManager.isActualTransactionActive());
System.out.println("B method 当前事务name : "+ TransactionSynchronizationManager.getCurrentTransactionName());
bnMapper.deleteB(bId);
System.out.println("B method 当前事务id : "+ TransactionalId.getTransactionalId());
}
运行结果:这种属于,A method是在事务中,A 异常会回滚,B由于不在事务中执行,所以会被执行。
验证:表a没有插入数据库,表b中对应的数据被删除。
7.4 A 开启事务;B 事务传播行为:NOT_SUPPORTED;B 抛出异常,A不捕获
@Test
public void notSupportsTest_4(){
A a = new A();
a.setName("诺诺罗亚");
a.setSex("男");
Integer bId = 12;
anNotSupportedTransactionalService.anNoSupportedTest_4(a,bId);
}
@Transactional
@Override
public void anNoSupportedTest_4(A a, Integer bId) {
System.out.println("A method 返回当前是否有实际事务处于活动状态 : "+ TransactionSynchronizationManager.isActualTransactionActive());
System.out.println("A method 当前事务name : " + TransactionSynchronizationManager.getCurrentTransactionName());
anMapper.insertSelective(a);
System.out.println("A method 当前事务id : "+ TransactionalId.getTransactionalId());
bnNotSupportedTransactionalService.bnNoSupportedTest_2(bId);
}
@Transactional(propagation = Propagation.NOT_SUPPORTED)
@Override
public void bnNoSupportedTest_2(Integer bId) {
System.out.println("B method 返回当前是否有实际事务处于活动状态 : " + TransactionSynchronizationManager.isActualTransactionActive());
System.out.println("B method 当前事务name : "+ TransactionSynchronizationManager.getCurrentTransactionName());
bnMapper.deleteB(bId);
System.out.println("B method 当前事务id : "+ TransactionalId.getTransactionalId());
// 异常在数据库操作的后面
int f = 2/0;
}
运行结果:(注意:B 抛出异常,抛出的异常在数据库操作后面)
A的insert操作回滚,B的delete的操作正常执行。
7.5 A 开启事务;B 事务传播行为:NOT_SUPPORTED;B 抛出异常,A捕获
@Test
public void notSupportsTest_5(){
A a = new A();
a.setName("诺诺罗亚");
a.setSex("男");
Integer bId = 12;
anNotSupportedTransactionalService.anNoSupportedTest_5(a,bId);
}
@Transactional
@Override
public void anNoSupportedTest_5(A a, Integer bId) {
System.out.println("A method 返回当前是否有实际事务处于活动状态 : "+ TransactionSynchronizationManager.isActualTransactionActive());
System.out.println("A method 当前事务name : " + TransactionSynchronizationManager.getCurrentTransactionName());
anMapper.insertSelective(a);
System.out.println("A method 当前事务id : "+ TransactionalId.getTransactionalId());
// 捕获异常
try {
bnNotSupportedTransactionalService.bnNoSupportedTest_2(bId);
}catch (RuntimeException e){
e.printStackTrace();
}
}
@Transactional(propagation = Propagation.NOT_SUPPORTED)
@Override
public void bnNoSupportedTest_2(Integer bId) {
System.out.println("B method 返回当前是否有实际事务处于活动状态 : " + TransactionSynchronizationManager.isActualTransactionActive());
System.out.println("B method 当前事务name : "+ TransactionSynchronizationManager.getCurrentTransactionName());
bnMapper.deleteB(bId);
System.out.println("B method 当前事务id : "+ TransactionalId.getTransactionalId());
// 异常在数据库操作的后面
int f = 2/0;
}
运行结果:
A,B都没有回滚。
A的insert操作正常执行,B的delete的操作也正常执行。
八、NEVER
- NEVER
- 表示当方法务不应该在一个事务中运行,如果存在一个事务,则抛出异常;
- 1、A 不开启事务,B 传播行为为:NEVER
- 结果:A,B方法都没有在事务中运行
- 2、A 开启事务,B 传播行为为:NEVER
- 结果:抛出异常 IllegalTransactionStateException: Existing transaction found for transaction marked with propagation 'never'
8.1 A 不开启事务,B 传播行为:NEVER
@Test
public void neverTest_1(){
A a = new A();
a.setName("尼卡");
a.setSex("男");
Integer bId = 12;
anNeverTransactionalService.anRequiredTest_1(a,bId);
}
@Override
public void anRequiredTest_1(A a, Integer bId) {
System.out.println("A method 返回当前是否有实际事务处于活动状态 : "+ TransactionSynchronizationManager.isActualTransactionActive());
System.out.println("A method 当前事务name : "+ TransactionSynchronizationManager.getCurrentTransactionName());
anMapper.insertSelective(a);
bnNeverTransactionalService.bnRequiredTest_1(bId);
}
@Transactional(propagation = Propagation.NEVER)
@Override
public void bnRequiredTest_1(Integer id) {
System.out.println("B method 返回当前是否有实际事务处于活动状态 : " + TransactionSynchronizationManager.isActualTransactionActive());
System.out.println("B method 当前事务name : "+ TransactionSynchronizationManager.getCurrentTransactionName());
bnMapper.deleteB(id);
}
运行结果:
打印日志: A method 返回当前是否有实际事务处于活动状态 : false A method 当前事务name : null B method 返回当前是否有实际事务处于活动状态 : false B method 当前事务name : com.transactional.service.impl.never.BnNeverTransactionalServiceImpl.bnRequiredTest_1
通过上面打印日志可以看到,A,B方法都没有在事务中运行
8.2 A 开启事务,B 传播行为为:NEVER
@Test
public void neverTest_2(){
A a = new A();
a.setName("尼卡");
a.setSex("男");
Integer bId = 12;
anNeverTransactionalService.anRequiredTest_2(a,bId);
}
@Transactional
@Override
public void anRequiredTest_2(A a, Integer bId) {
System.out.println("A method 返回当前是否有实际事务处于活动状态 : "+ TransactionSynchronizationManager.isActualTransactionActive());
System.out.println("A method 当前事务name : "+ TransactionSynchronizationManager.getCurrentTransactionName());
anMapper.insertSelective(a);
bnNeverTransactionalService.bnRequiredTest_1(bId);
}
@Transactional(propagation = Propagation.NEVER)
@Override
public void bnRequiredTest_1(Integer id) {
System.out.println("B method 返回当前是否有实际事务处于活动状态 : " + TransactionSynchronizationManager.isActualTransactionActive());
System.out.println("B method 当前事务name : "+ TransactionSynchronizationManager.getCurrentTransactionName());
bnMapper.deleteB(id);
}
运行结果:A,B都会回滚,并抛出异常 IllegalTransactionStateException: Existing transaction found for transaction marked with propagation 'never'
九、NESTED
补充:
- 1、一个数据库事务的知识:数据库的嵌套事务,嵌套事务其实就是一个savepoint,一个保存点,内层事务的异常回滚只是恢复到了上一个savepoint!!! 下面我们会证实,A,B处于同一事务中。
- 2、因为 spring 默认的数据源 不支持嵌套事务:NestedTransactionNotSupportedException: JpaDialect does not support savepoints - check your JPA provider's capabilities 所以在测试这个嵌套事务的时候利用 JdbcTemplate测试。
- NESTED
- 如果存在当前事务,则在嵌套事务中执行,如果不存在当前事务,那么就新开启一个事务。
- 1、 A method 不存在事务,B事务传播行为NESTED
- 结果:则B method()运行在一个新的事务中。
- 2、 A method()存在事务,B事务传播行为NESTED
- 结果:B method()运行在嵌套事务中,(这就是上面补充说道的,在同一个事务,只是有保存点。)
- 3、 A 作为外层事务,B 作为内层事务;A 发生异常
- 结果:A,B都回滚;
- 4、A 作为外层事务,B 作为内层事务;B 发生异常,A不捕获
- 结果:A,B都回滚;
- 5、A 作为外层事务,B 作为内层事务;B 发生异常,A捕获
- 结果:B method发生异常,B回滚不影响A事务的提交。(也就是B的回滚,只是回滚到了上一个保存点)
9.1 A 不存在事务,B 传播行为 NESTED
@Test
public void nestedTest_1(){
A a = new A();
a.setName("王麻子");
a.setSex("男");
Integer bId = 11;
anNestedTransactionalService.anNestedTest_1(a,bId);
}
@Override
public void anNestedTest_1(A a, Integer bId) {
System.out.println("A method 返回当前是否有实际事务处于活动状态 : "+ TransactionSynchronizationManager.isActualTransactionActive());
System.out.println("A method 当前事务name : "+ TransactionSynchronizationManager.getCurrentTransactionName());
jdbcTemplate.execute("insert into a(name,sex) values('"+a.getName()+"','"+a.getSex()+"')");
System.out.println("A method 当前事务 Id : "+ TransactionalId.getTransactionalId());
bnNestedTransactionalService.bnNestedTest_1(bId);
}
@Transactional(propagation = Propagation.NESTED)
@Override
public void bnNestedTest_1(Integer bId) {
System.out.println("B method 返回当前是否有实际事务处于活动状态 : " + TransactionSynchronizationManager.isActualTransactionActive());
System.out.println("B method 当前事务name : "+ TransactionSynchronizationManager.getCurrentTransactionName());
jdbcTemplate.execute("delete from b where id = '"+bId+"'");
System.out.println("B method 当前事务 Id : "+ TransactionalId.getTransactionalId());
}
运行结果:
打印结果: A method 返回当前是否有实际事务处于活动状态 : false A method 当前事务name : null A method 当前事务 Id : null B method 返回当前是否有实际事务处于活动状态 : true B method 当前事务name : com.transactional.service.impl.nested.BnNestedTransactionalServiceImpl.bnNestedTest_1 B method 当前事务 Id : null
从打印结果可以看到:B事务传播行为NESTED,B method()事务状态处于活动状态,运行在一个新的事务中 但是,为啥事务id为 null呀,我擦!!!
9.2 A 存在事务,B传播行为 NESTED
@Test
public void nestedTest_2(){
A a = new A();
a.setName("王麻子");
a.setSex("男");
Integer bId = 11;
anNestedTransactionalService.anNestedTest_2(a,bId);
}
@Transactional
@Override
public void anNestedTest_2(A a, Integer bId) {
System.out.println("A method 返回当前是否有实际事务处于活动状态 : "+ TransactionSynchronizationManager.isActualTransactionActive());
System.out.println("A method 当前事务name : "+ TransactionSynchronizationManager.getCurrentTransactionName());
jdbcTemplate.execute("insert into a(name,sex) values('"+a.getName()+"','"+a.getSex()+"')");
// 注意这里为啥写在 执行操作的后面!!!
System.out.println("A method 当前事务 Id : "+ TransactionalId.getTransactionalId());
bnNestedTransactionalService.bnNestedTest_1(bId);
}
@Transactional(propagation = Propagation.NESTED)
@Override
public void bnNestedTest_1(Integer bId) {
System.out.println("B method 返回当前是否有实际事务处于活动状态 : " + TransactionSynchronizationManager.isActualTransactionActive());
System.out.println("B method 当前事务name : "+ TransactionSynchronizationManager.getCurrentTransactionName());
jdbcTemplate.execute("delete from b where id = '"+bId+"'");
System.out.println("B method 当前事务 Id : "+ TransactionalId.getTransactionalId());
}
运行结果:
打印信息: A method 返回当前是否有实际事务处于活动状态 : true A method 当前事务name : com.transactional.service.impl.nested.AnNestedTransactionalServiceImpl.anNestedTest_2 A method 当前事务 Id : 155926 B method 返回当前是否有实际事务处于活动状态 : true B method 当前事务name : com.transactional.service.impl.nested.AnNestedTransactionalServiceImpl.anNestedTest_2 B method 当前事务 Id : 155926
可以看到确实是同一事务中。
9.3 A 作为外层事务,B 作为内层事务;A 发生异常
@Test
public void nestedTest_3(){
A a = new A();
a.setName("王麻子");
a.setSex("男");
Integer bId = 11;
anNestedTransactionalService.anNestedTest_3(a,bId);
}
@Transactional
@Override
public void anNestedTest_3(A a, Integer bId) {
System.out.println("A method 返回当前是否有实际事务处于活动状态 : "+ TransactionSynchronizationManager.isActualTransactionActive());
System.out.println("A method 当前事务name : "+ TransactionSynchronizationManager.getCurrentTransactionName());
jdbcTemplate.execute("insert into a(name,sex) values('"+a.getName()+"','"+a.getSex()+"')");
bnNestedTransactionalService.bnNestedTest_1(bId);
// 抛出运行时异常,注意把异常写在 两个数据操作完成之后的用意。
// 这样就可以保证了 两个内外事务都执行了,在A method发生了异常使得 A,B的数据库操作都回滚。
int f = 2/0;
}
@Transactional(propagation = Propagation.NESTED)
@Override
public void bnNestedTest_1(Integer bId) {
System.out.println("B method 返回当前是否有实际事务处于活动状态 : " + TransactionSynchronizationManager.isActualTransactionActive());
System.out.println("B method 当前事务name : "+ TransactionSynchronizationManager.getCurrentTransactionName());
jdbcTemplate.execute("delete from b where id = '"+bId+"'");
System.out.println("B method 当前事务 Id : "+ TransactionalId.getTransactionalId());
}
运行结果:A,B都回滚;可以查看数据库,a表没有插入数据,b表没有删除数据
9.4 A 作为外层事务,B 作为内层事务;B 发生异常,A不捕获
@Test
public void nestedTest_4(){
A a = new A();
a.setName("王麻子");
a.setSex("男");
Integer bId = 11;
anNestedTransactionalService.anNestedTest_4(a,bId);
}
@Transactional
@Override
public void anNestedTest_4(A a, Integer bId) {
System.out.println("A method 返回当前是否有实际事务处于活动状态 : "+ TransactionSynchronizationManager.isActualTransactionActive());
System.out.println("A method 当前事务name : "+ TransactionSynchronizationManager.getCurrentTransactionName());
jdbcTemplate.execute("insert into a(name,sex) values('"+a.getName()+"','"+a.getSex()+"')");
bnNestedTransactionalService.bnNestedTest_2(bId);
}
@Transactional(propagation = Propagation.NESTED)
@Override
public void bnNestedTest_2(Integer bId) {
System.out.println("B method 返回当前是否有实际事务处于活动状态 : " + TransactionSynchronizationManager.isActualTransactionActive());
System.out.println("B method 当前事务name : "+ TransactionSynchronizationManager.getCurrentTransactionName());
jdbcTemplate.execute("delete from b where id = '"+bId+"'");
System.out.println("B method 当前事务 Id : "+ TransactionalId.getTransactionalId());
int f = 2/0;
}
运行结果:A,B都回滚;
因为 A,B还是在同一个事务中,B异常,A如果不做处理,那就整个事务回滚。
9.5 A 作为外层事务,B 作为内层事务;B 发生异常,A捕获
@Test
public void nestedTest_5(){
A a = new A();
a.setName("王麻子");
a.setSex("男");
Integer bId = 11;
anNestedTransactionalService.anNestedTest_5(a,bId);
}
@Transactional
@Override
public void anNestedTest_5(A a, Integer bId) {
System.out.println("A method 返回当前是否有实际事务处于活动状态 : "+ TransactionSynchronizationManager.isActualTransactionActive());
System.out.println("A method 当前事务name : "+ TransactionSynchronizationManager.getCurrentTransactionName());
jdbcTemplate.execute("insert into a(name,sex) values('"+a.getName()+"','"+a.getSex()+"')");
try {
bnNestedTransactionalService.bnNestedTest_2(bId);
}catch (RuntimeException e){
e.printStackTrace();
}
}
@Transactional(propagation = Propagation.NESTED)
@Override
public void bnNestedTest_2(Integer bId) {
System.out.println("B method 返回当前是否有实际事务处于活动状态 : " + TransactionSynchronizationManager.isActualTransactionActive());
System.out.println("B method 当前事务name : "+ TransactionSynchronizationManager.getCurrentTransactionName());
jdbcTemplate.execute("delete from b where id = '"+bId+"'");
System.out.println("B method 当前事务 Id : "+ TransactionalId.getTransactionalId());
int f = 2/0;
}
运行结果:B method发生异常,B回滚不影响A事务的提交。(也就是B的回滚,只是回滚到了上一个保存点)
数据库结果:A insert操作正常插入,B delete操作回滚。
转载自:https://juejin.cn/post/7392071148751994932