Spring中,@Transactional 注解的失效测试以及传播行为测试

分别测试四种情况:

  1. 同一个service中,A方法调用B方法,B方法抛异常
  2. 同一个service中,A方法调用B方法,A方法抛异常
  3. service1中A方法,调用service2中B方法,B方法抛异常
  4. service1中A方法,调用service2中B方法,A方法抛异常

分别测试A、B方法加上@Transactional注解

Controller层:

@RestController
@RequestMapping(value = "/transaction")
public class TransactionController {

	@Autowired
	TransactionService transactionService;
	
	@GetMapping(value="/test")
	public String test() {
		return transactionService.test();
	}
}

Dao层:

@Mapper
public interface TransactionDao {

	@Insert(value = "insert into test(name) values ('小明')")
	public void insertUser();

	@Insert(value = "insert into test(name) values ('小李')")
	public void insertAnotherUser();
}

Service1:

@Service
public class TransactionService {

	@Autowired
	TransactionDao transactionDao;
	
	@Autowired
	TransactionServiceB transactionServiceB;
	
	public String test() {
		transactionDao.insertUser();
		return "success";
	}
	
	public void testException() {
		transactionDao.insertAnotherUser();
		throw new RuntimeException();
	}

}

Service2:

@Service
public class TransactionServiceB {

	public void testException() {
		transactionDao.insertAnotherUser();
		throw new RuntimeException();
	}
}

测试地址:http://localhost:8080/transaction/test

一、同一个service中,A方法调用B方法,B方法抛异常

1.1 方法A加@Transactional注解,方法B不加@Transactional注解

Service:

	@Transactional
	public String test() {
		transactionDao.insertUser();
		testException();
		return "success";
	}
	
	public void testException() {
		transactionDao.insertAnotherUser();
		throw new RuntimeException();
	}

结果:
在这里插入图片描述
数据库:
在这里插入图片描述
事务成功回滚

1.2 方法A加@Transactional注解,方法B加@Transactional注解

Service:

	@Transactional
	public String test() {
		transactionDao.insertUser();
		testException();
		return "success";
	}
	
	@Transactional
	public void testException() {
		transactionDao.insertAnotherUser();
		throw new RuntimeException();
	}

结果:
在这里插入图片描述
数据库:
在这里插入图片描述
事务成功回滚

1.3 方法A不加@Transactional注解,方法B加@Transactional注解

Service:

	public String test() {
		transactionDao.insertUser();
		testException();
		return "success";
	}
	
	@Transactional
	public void testException() {
		transactionDao.insertAnotherUser();
		throw new RuntimeException();
	}

结果:
在这里插入图片描述
数据库:
在这里插入图片描述
事务没有回滚,B方法上的@Transactional注解失效。由于中间重置了一下自增的序列,因此id是从3开始,下面可以看到正常的主键的id的跳跃

二、 同一个service中,A方法调用B方法,A方法抛异常

2.1 方法A加@Transactional注解,方法B不加@Transactional注解

Service:

	@Transactional
	public String test() {
		transactionDao.insertUser();
		testException();
		throw new RuntimeException();
	}
	
	public void testException() {
		transactionDao.insertAnotherUser();
	}

结果:
在这里插入图片描述
数据库:
在这里插入图片描述
事务成功回滚

2.2 方法A加@Transactional注解,方法B加@Transactional注解

Serice:

	@Transactional
	public String test() {
		transactionDao.insertUser();
		testException();
		throw new RuntimeException();
	}
	
	@Transactional
	public void testException() {
		transactionDao.insertAnotherUser();
	}

结果:
在这里插入图片描述
数据库:
在这里插入图片描述
事务成功回滚

2.3 方法A不加@Transactional注解,方法B加@Transactional注解

Service:

	public String test() {
		transactionDao.insertUser();
		testException();
		throw new RuntimeException();
	}
	
	@Transactional
	public void testException() {
		transactionDao.insertAnotherUser();
	}

结果:
在这里插入图片描述
数据库:
在这里插入图片描述
事务没有回滚,B方法上的@Transactional注解失效,同时自增也间隔了4,说明之前的4次插入数据的回滚,会影响自增的递增

三、 service1中A方法,调用service2中B方法,B方法抛异常

3.1 方法A加@Transactional注解,方法B不加@Transactional注解

Service1:

	@Transactional
	public String test() {
		transactionDao.insertUser();
		transactionServiceB.testException();
		return "success";
	}

Service2:

	public void testException() {
		transactionDao.insertAnotherUser();
		throw new RuntimeException();
	}

结果:
在这里插入图片描述
数据库:
在这里插入图片描述
事务回滚成功

3.2 方法A加@Transactional注解,方法B加@Transactional注解

Service1:

	@Transactional
	public String test() {
		transactionDao.insertUser();
		transactionServiceB.testException();
		return "success";
	}

Service2:

	@Transactional
	public void testException() {
		transactionDao.insertAnotherUser();
		throw new RuntimeException();
	}

结果:
在这里插入图片描述
数据库:
在这里插入图片描述
事务回滚成功

3.3 方法A不加@Transactional注解,方法B加@Transactional注解

Service1:

	public String test() {
		transactionDao.insertUser();
		transactionServiceB.testException();
		return "success";
	}

Service2:

	@Transactional
	public void testException() {
		transactionDao.insertAnotherUser();
		throw new RuntimeException();
	}

结果:
在这里插入图片描述
数据库:
在这里插入图片描述
Service1中没有事务,也没有回滚,Service2中的事务成功回滚

四、 service1中A方法,调用service2中B方法,A方法抛异常

4.1 方法A加@Transactional注解,方法B不加@Transactional注解

Service1:

	@Transactional
	public String test() {
		transactionDao.insertUser();
		transactionServiceB.testException();
		throw new RuntimeException();
	}

Service2:

	public void testException() {
		transactionDao.insertAnotherUser();
	}

结果:
在这里插入图片描述
数据库:
在这里插入图片描述
事务回滚成功

4.2 方法A加@Transactional注解,方法B加@Transactional注解

Service1:

	@Transactional
	public String test() {
		transactionDao.insertUser();
		transactionServiceB.testException();
		throw new RuntimeException();
	}

Service2:

	@Transactional
	public void testException() {
		transactionDao.insertAnotherUser();
	}

结果:
在这里插入图片描述
数据库:
在这里插入图片描述
事务回滚成功,同时可以说明,默认的传播行为REQUIRED,一会可以测试一下其他的传播机制

4.3 方法A不加@Transactional注解,方法B加@Transactional注解

Service1:

	public String test() {
		transactionDao.insertUser();
		transactionServiceB.testException();
		throw new RuntimeException();
	}

Service2:

	@Transactional
	public void testException() {
		transactionDao.insertAnotherUser();
	}

结果:
在这里插入图片描述
数据库:
在这里插入图片描述
Service1中没有事务,也没有进行回滚

五、测试其他传播机制

5.1 采用4.2 方法A加@Transactional注解,方法B加@Transactional注解进行测试,A方法抛出异常,修改方法B的传播机制

Service1:

	@Transactional
	public String test() {
		transactionDao.insertUser();
		transactionServiceB.testException();
		throw new RuntimeException();
	}

Service2:

	@Transactional(propagation = Propagation.REQUIRES_NEW)
	public void testException() {
		transactionDao.insertAnotherUser();
	}

结果:
在这里插入图片描述
数据库:
在这里插入图片描述
可以看到,Service1中的事务成功回滚,Service2中由于新开启了一个事务,所以Service1中的回滚,并不会影响Service2中的数据的提交

5.2 采用3.2 方法A加@Transactional注解,方法B加@Transactional注解进行测试,B方法抛出异常,修改方法B的传播机制

Service1:

	@Transactional
	public String test() {
		transactionDao.insertUser();
		transactionServiceB.testException();
		return "success";
	}

Service2:

	@Transactional(propagation = Propagation.REQUIRES_NEW)
	public void testException() {
		transactionDao.insertAnotherUser();
		throw new RuntimeException();
	}

结果:
在这里插入图片描述
数据库:
在这里插入图片描述
Service1和Sevice2中的事务都成功回滚

再进行一个尝试,A方法中捕获一下异常
Service1:

	@Transactional
	public String test() {
		transactionDao.insertUser();
		try {
			transactionServiceB.testException();
		} catch (Exception e) {
			return e.getMessage();
		}
		return "success";
	}

Service2:

	@Transactional(propagation = Propagation.REQUIRES_NEW)
	public void testException() {
		transactionDao.insertAnotherUser();
		throw new RuntimeException();
	}

结果:
返回空

数据库:
在这里插入图片描述
Service1中捕获了异常,因此Service1中的事务可以正常提交,Service2中由于出现异常,事务进行了回滚

六、 总结

同一个类中,A方法调用B方法,此时B方法的@Transactional注解是无效的,因为没有经过Spring的代理,直接对方法进行了调用,所以注解没有办法被AOP扫描到,就不能实现事务的功能。

不同类中,A方法调用B方法,此时B方法的@Transactional注解是生效的,因为经过了Spring的代理。此时A方法或者B方法中出现异常,是否回滚需要看事务的传播行为,以及异常是否进行了捕获。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
@Transactional注解失效的情况有以下几种: 1. 方法没有被Spring代理 - 由于Spring的事务管理是基于AOP实现的,所以只有被Spring代理的方法才会被@Transactional注解所识别。如果方法没有被代理,那么@Transactional注解将无效。 2. 异常被catch住 - 如果在带有@Transactional注解的方法,捕获了异常并且没有再次抛出,那么事务将不会回滚。事务只有在未被捕获的异常发生时才会回滚。 3. 事务方法内部调用 - 如果在同一个类的方法内部调用带有@Transactional注解的方法,那么事务注解将无效。这是因为Spring使用基于代理的事务管理,而同一个类的方法调用并不会通过代理。 4. 异常不属于rollbackFor指定的类型 - @Transactional注解的rollbackFor参数可以指定回滚的异常类型。如果抛出的异常不属于指定的类型,事务将不会回滚。 5. 事务方法是私有的、final的或静态的 - @Transactional注解只能应用于public方法。私有的、final的或静态的方法无法被事务管理。 6. 异常被try-catch重新抛出并修改了异常类型 - 如果在带有@Transactional注解的方法,捕获了异常并在重新抛出时修改了异常类型,那么事务将不会回滚。事务回滚是基于异常类型的匹配,修改异常类型会导致匹配失败[3]。 7. 方法内部调用self method - 如果在同一个类的方法内部调用了自身的方法,事务注解将无效。这是因为同一个类的方法调用不会通过代理,所以事务注解不会生效。 以上是一些常见的@Transactional注解失效的情况,需要注意这些情况以确保事务能够正确地生效。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [@Transactional注解失效的情况](https://blog.csdn.net/qq_40834643/article/details/128535431)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值