聊聊@Transactional注解那些不生效的坑

本文深入探讨SpringBoot中声明式事务的常见误区,包括@Transcational注解的使用限制、运行时异常处理及方法调用的事务边界问题,并提供了解决方案。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

随着SpringBoot在开发中的广泛使用,声明式事务得到了越来越多的认可。一个@Transactional注解就可以搞定事务,可是如果对事务和该注解的认识不足,往往会给开发带来一些bug。

1.一个@Transcational真的就够了吗?

@Transactional
public void testRollBack() throws SQLException {
    User user = User.builder().u_name("Tom").age(18).build();
    userMapper.insert(user);
    // 一些业务代码 产生的检测异常
    throw new SQLException();
}

请问这段代码事务会回滚吗?
事实告诉我们,这段代码其实不会回滚该异常。那么为什么呢?原因在于@Trancational注解默认情况下只会回滚运行时异常RunTimeExcetion)和错误Error

@Override
public boolean rollbackOn(Throwable ex) {
	return (ex instanceof RuntimeException || ex instanceof Error);
}

这段代码来自org.springframework.transaction.interceptor.DefaultTransactionAttribute

那么在开发中如果需要回滚检测异常怎么办呢?其实只须加上下列代码即可,将异常放大到Exception.

@Transactional(rollbackFor = Exception.class)

平时写代码的时候,sql错了(java.sql.SQLSyntaxErrorException继承于SqlException,非运行时异常),事务不也照常回滚吗?这是因为框架帮我们捕获了该异常,对Aop事务抛出的运行时异常,所以事务回滚了。

2.运行时异常为何不回滚?

@Override
@Transactional(rollbackFor = Exception.class)
public void testRollBack() {
   User user = User.builder().u_name("Tom").age(18).build();
   userMapper.insert(user);
   try {
       // 业务代码
       throw new RuntimeException("");
   } catch (Exception e){
       log.warn("警告日志");
   }
}

请问这段代码事务会回滚吗?
事实再次告诉我们,事务不会回滚。这是因为Spring提供的事务机制,其实也是try catch 这种形式,当Spring无法捕获到异常时,就会认为这段代码正常,而不会回滚,因此,如果当你的业务需要回滚时,一定要将你捕获的异常再次抛出,让Spring感知你的异常,这样才会回滚。

3.调用一个同类(或父类)的方法为何不回滚?

@Override
public void testRollBack() {
   	insert();
 }

 @Transactional(rollbackFor = Exception.class)
 public void insert(){
     User user = User.builder().u_name("Tom").age(18).build();
     userMapper.insert(user);
     throw new RuntimeException();
 }

实际上这段代码也不会回滚的。这是因为Spring的事务机制是基于Aop的切面编程,而切面是依附于类的,从web层->service层涉及到切面了,因此事务是生效的,而service层内部的调用,是不涉及类与类之间的调用,spring自然也不会感知到Aop。
上述代码是同类的调用,实际上子类调用父类的方法也会生效。
那么如何解决这个问题呢?一种方法是将@Transaction注解移到testRollBack()方法上,另一种方法是将事务类方法做业务代码的下层,放在一个新的类中,用当前类去调用新类中的方法,这样事务就会生效。这种方法适合于业务代码复杂,事务代码可以集中在一处。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值