SpringBoot-@Transactional注解失效

@Transactional注解失效

@Transactional失效场景

以下是一些常见导致@Transactional注解失效的场景,配合相应的Java代码演示:

1、方法修饰符非公开(非public

@Transactional注解失效的原因在于Spring事务管理器如何实现对事务的代理和管理。Spring使用AOP(面向切面编程)机制来处理@Transactional注解的方法。具体而言,Spring会在运行时为带有@Transactional注解的Bean创建一个代理对象,代理对象负责在方法调用前后添加事务的开始、提交或回滚等逻辑。

当方法修饰符为非公开(非public)时,导致@Transactional失效的原因主要有以下两点:

  1. AOP代理的默认行为
    Spring AOP默认仅对public方法进行代理增强。这是因为Spring使用JDK动态代理(对于接口代理)或CGLIB代理(对于类代理)来创建代理对象。这两种代理方式均基于继承或接口实现,对非public方法的代理存在技术上的限制。JDK动态代理只能代理接口方法,自然无法代理非public方法;CGLIB虽然可以代理类的非public方法,但Spring AOP的默认配置并不包括对非public方法的增强。

  2. 设计原则与最佳实践
    从设计原则和最佳实践的角度考虑,服务层方法通常应该对外提供明确的、有限的接口(即public方法),而将内部细节(如非public方法)隐藏起来。因此,@Transactional注解通常应用于服务层的业务方法,这些方法通常是public的,以便外部调用。非public方法通常用于实现具体的业务逻辑,如果它们需要参与到事务管理中,通常是因为它们被某个@Transactional注解的public方法调用,此时事务管理应由调用方(即public方法)负责。

综上所述,由于Spring AOP的默认行为和设计原则的考量,非public方法上的@Transactional注解通常不会被Spring事务管理器识别和处理,从而导致事务注解失效。若确实需要对非public方法进行事务管理,通常需要调整Spring的AOP配置,或者更改为在调用这些方法的public方法上添加@Transactional注解。然而,这并不符合最佳实践,通常建议将事务边界设定在对外提供的public方法上。
在这里插入图片描述

2、内部方法调用

@Service
public class UserService {

    @Transactional
    public void updateUser() {
        // 调用内部私有方法,事务不会传播到此方法
        processUpdate();
    }

    // @Transactional在此处无效,因为是通过非代理对象直接调用
    private void processUpdate() {
        // 更新数据库操作...
    }
}
  1. 异常捕获但未抛出

    @Service
    public class OrderService {
    
        @Transactional
        public void placeOrder() {
            try {
                // 执行可能抛出异常的操作
                saveOrderDetails();
                // 其他业务逻辑...
            } catch (Exception e) {
                // 异常被捕获但未重新抛出,事务不会回滚
                log.error("An error occurred while placing the order", e);
            }
        }
    
        private void saveOrderDetails() throws SQLException {
            // 可能抛出SQLException的数据库操作
        }
    }
    
  2. 事务传播设置不当

    @Service
    public class TransactionalServiceA {
    
        @Transactional(propagation = Propagation.NEVER)
        public void nonTransactionalMethod() {
            // 如果此方法在另一个已开启事务的方法中被调用,由于传播设置为NEVER,此处事务将不会生效
            performTransactionalOperation();
        }
    
        @Transactional
        private void performTransactionalOperation() {
            // 应该在事务中执行的操作
        }
    }
    
  3. 配置问题:未启用代理模式或代理对象未被正确使用

    // 假设配置中未启用Spring AOP代理(如使用了CGLIB代理而非JDK动态代理)
    // 或者在某些情况下直接通过new关键字创建了Service实例,而非依赖注入
    UserService userService = new UserService();
    
    // 由于userService不是由Spring容器管理的代理对象,@Transactional将失效
    userService.updateDataInTransaction();
    
  4. 事务超时或并发控制设置冲突

    @Service
    public class InventoryService {
    
        @Transactional(timeout = 1)  // 设置较短的事务超时时间
        public void adjustStock() {
            // 长时间运行的数据库操作,可能导致事务超时而提前结束,不保证原子性
            // ...
        }
    }
    

以上代码示例展示了可能导致@Transactional注解失效的几种常见场景。在实际使用中,应确保正确配置Spring事务管理器、合理设置事务属性,并遵循Spring AOP代理的使用规则,以确保事务功能正常运作。

  • 18
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小孔靠得住

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值