@Transactional事务失效的10个场景


总结

例如:随着人工智能的不断发展,机器学习这门技术也越来越重要,很多人都开启了学习机器学习,本文就介绍了机器学习的基础内容。
1、同一个类中,方法内部调用事务失效

2、事务方法被final、static修饰

3、当前类没有被Spring管理

4、非public修饰的方法(存在版本差异)

5、事务多线程调用

6、数据库本身不支持事务

7、异常被方法内部try catch捕获,没有重新抛出

8、嵌套事务回滚多了

9、rollbackFor属性设置错误

10、设置不支持事务的传播机制


1、同一个类中,方法内部调用事务失效(代理不生效导致)

示例:同一个类中,addOrder()方法无事务,addOrder2()方法存在事务,addOrder()调用addOrder2()是失效的(非事务方法调用事务方法是无效的

@Service
public class OrderServiceImpl {

    @Autowired
    private OrderMapper orderMapper;

    public int addOrder(Double amount, String address) {
        int order = addOrder2(amount, address);
        return order;
    }

    @Transactional
    public int addOrder2(Double amount, String address) {
        int order = orderMapper.addOrder(amount, address);
        int i = order / 0;
        return order;
    }
}

解决方案:


@Service
public class OrderServiceImpl {

    @Autowired
    private OrderMapper orderMapper;

    @Transactional
    public int addOrder(Double amount, String address) {
        int order = addOrder2(amount, address);
        return order;
    }

    @Transactional
    public int addOrder2(Double amount, String address) {
        int order = orderMapper.addOrder(amount, address);
        int i = order / 0;
        return order;
    }
}

2、事务方法被final、static修饰

事务失效的示例:

@Service
public class OrderServiceImpl {

    @Autowired
    private OrderMapper orderMapper;

    @Transactional
    public final int addOrder(Double amount, String address) {
        int order = orderMapper.addOrder(amount, address);
        int i = order / 0;
        return order;
    }
    @Transactional
    public int addOrder2(Double amount, String address) {
        int order = orderMapper.addOrder(amount, address);
        int i = order / 0;
        return order;
    }
 }

3、当前类没有被Spring管理

例如:Service类中没有@Service注解

public class OrderServiceImpl {
    @Autowired
    private OrderMapper orderMapper;
    @Transactional
    public int addOrder(Double amount, String address) {
        int order = orderMapper.addOrder(amount, address);
        int i = order / 0;
        return order;
    }
}

@Transactional事务生效的前提条件是需要代理类对目标方法的调用,才能触发事务处理,而代理类是在springBoot启动时创建bean的时候处理的。如果我们的类没有@Service注解,就不会交给spring容器初始化处理,也就无法为目标类生成代理类。

4、非public修饰的方法(存在版本差异)

在spring版本6.0.11中@Transactional是支持proected修饰的方法的


@Service
public class OrderServiceImpl {
    @Autowired
    private OrderMapper orderMapper;
    @Transactional
    protected int addOrder(Double amount, String address) {
        int order = orderMapper.addOrder(amount, address);
        int i = order / 0;
        return order;
    }
}

5、事务多线程调用

示例代码:


@Service
public class OrderServiceImpl {
    @Autowired
    private OrderMapper orderMapper;
    @Autowired
    private SysUserServiceImpl sysUserService;

    @Transactional(rollbackFor = Exception.class)
    public int addOrder(Double amount, String address){
        int order = orderMapper.addOrder(amount, address);
        new Thread(() -> {
            sysUserService.saveUser();
        }).start();

        return order;
    }
}

6、数据库本身不支持事务

Spring事务的底层,还是依赖于数据库本身的事务支持。在MySQL中,Myisam存储引擎是不支持事务的,InnoDB引擎才支持事务

这种问题出现的概率很小,在Mysql5之后,默认情况下是使用的InnoDB引擎存储

如果是历史项目,发现事务怎么配置都不生效,确认下你的存储引擎是否支持事务。

7.异常被方法内部try catch捕获,没有重新抛出

示例代码:


@Service
public class OrderServiceImpl {
    @Autowired
    private OrderMapper orderMapper;

    @Transactional
    public int addOrder(Double amount, String address) {
        int order = 0;
        try {
            order = orderMapper.addOrder(amount, address);
            int i = order / 0;
        } catch (Exception e) {
        }

        return order;
    }
}

8、嵌套事务回滚多了

示例代码:


@Service
public class OrderServiceImpl {
    @Autowired
    private OrderMapper orderMapper;
    @Autowired
    private SysUserServiceImpl sysUserService;

    @Transactional(rollbackFor = Exception.class)
    public int addOrder(Double amount, String address){
        int order = orderMapper.addOrder(amount, address);
        sysUserService.saveUser();
        return order;
    }
}
@Service
public class SysUserServiceImpl {

    @Transactional
    public void saveUser(){
        throw new RuntimeException("新增人员失败");
    }
}

当出现嵌套事务发生异常的时候,实际上两个方法的事务都会进行回滚。

但是有一种场景,即使sysUserService.saveUser()方法发生异常,我们期望orderMapper.addOrder()方法执行的结果也正常入库。

解决办法:

1、addOrder()方法使用trye/catch包住

2、saveUser()方法的事务传播机制调整为Propagation.REQUIRES_NEW

9、rollbackFor属性设置错误

示例代码:


@Service
public class OrderServiceImpl {
    @Autowired
    private OrderMapper orderMapper;

    @Transactional
    public int addOrder(Double amount, String address) throws FileNotFoundException {
        int order = orderMapper.addOrder(amount, address);
        throw new FileNotFoundException("11111");
    }
}

@Transactional,在未对rollbackFor做配置的情况下,默认是支持对Runtime和Error异常的回滚的。
而在示例代码中,我们手动的抛出FileNotFountException异常,这是一个IOException异常,是无法回滚异常的。
所以通常情况下,建议指定@Transactional(rollbackFor = Exception.class)的方式进行异常捕获。

10、设置了不支持事务的传播机制

Spring支持了7种传播机制,分别为:
在这里插入图片描述
上面不支持事务的传播机制为(如果配置了这三种传播方式的话,在发生异常的时候,事务是不会回滚的):
PROPAGATION_SUPPORTS
PROPAGATION_NOT_SUPPORTED
PROPAGATION_NEVER
示例代码:


@Service
public class OrderServiceImpl {
    @Autowired
    private OrderMapper orderMapper;

    @Transactional(rollbackFor = Exception.class, propagation = Propagation.SUPPORTS)
    public int addOrder(Double amount, String address) throws FileNotFoundException {
        int order = orderMapper.addOrder(amount, address);
        throw new FileNotFoundException("11111");
    }
}

  • 16
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
@Transactional注解失效场景有以下几种情况: 1. 异常被catch并处理: 当一个使用@Transactional注解标记的方法中发生异常时,如果异常被catch并在方法内部进行了处理,那么事务将不会回滚。这是因为Spring默认只会对未被捕获的异常进行回滚处理。 2. 事务方法内部调用其他事务方法: 如果一个使用@Transactional注解标记的方法内部调用了另一个使用@Transactional注解标记的方法,而内部方法没有抛出异常,则外部方法的事务将无效。原因是Spring默认使用了基于代理的事务机制,而代理是通过AOP实现的。在同一个类中,使用@Transactional注解标记的方法调用其他使用@Transactional注解标记的方法,事务失效。 3. 基于自调用的事务: 当一个使用@Transactional注解标记的方法内部调用了自身(即自循环),而且没有使用代理的方式进行调用,事务也会失效。这是因为代理是通过AOP实现的,自调用会绕过代理,导致事务无法生效。 4. 异步方法: 在使用Spring的异步方法时,如果在异步方法内部使用了@Transactional注解标记的方法,事务将无效。这是因为异步方法会在一个新的线程中执行,而事务是基于线程的。因此,在异步方法中使用事务注解是无效的。 5. protected或private方法: 当使用@Transactional注解标记的方法是protected或private修饰的时候,事务也会失效。尽管没有报错,但事务并不会起作用。这是一个常见的错误点,需要特别注意。 综上所述,需要注意以上情况,以确保@Transactional注解的正确使用和事务的生效。如果遇到上述场景,可以考虑使用其他方式来实现事务控制,如编程式事务管理或通过代理对象调用。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值