Spring为什么加了事务却没生效

Spring为什么加了事务却没生效

​ Spring针对事务的管理是通过动态代理实现的,那么事务要进行传播首先必须要是被代理的方法之间,这是Spring事务传播的前提。比如:如果在同一个service里两个方法:方法A,方法B上都加了Transactional()

并且用方法A直接调用了方法B此时方法B上的注解Transactional并不生效(具体原因会新增文章说明跟动态代理的机制有关)。

//示例1
public class ClassA{
    //方法A
    @Transactional(propagation = Propagation.REQUIRED,rollbackFor = Exception.class)
    a(){
        ...
        b();//此时b方法上添加的事务注解并不生效
    }
     //方法B
    @Transactional(propagation = Propagation.REQUIRES_NEW,rollbackFor = Exception.class)
    b(){
        ...
    }
}
事务传播生效示例
//示例2
public class ClassA{
    @Autowired
    private ClassB classB;
    //方法A
    @Transactional(propagation = Propagation.REQUIRED,rollbackFor = Exception.class)
    a(){
        ...
        classB.c();//此时c方法上添加的事务注解会生效
    }
     //方法B
    @Transactional(propagation = Propagation.REQUIRES_NEW,rollbackFor = Exception.class)
    b(){
        ...
    }
}
public class ClassB{
    @Transactional(propagation = Propagation.REQUIRES_NEW,rollbackFor = Exception.class)
    c(){
        ...
       c();
    }
}

Spring 事务传播属性对比

属性说明对比
PROPAGATION_REQUIRED如果当前没有事务,就新建一个事务,如果已经存在一个事务中,加入到这个事务中。这是最常见的选择,默认选择。常用的
PROPAGATION_SUPPORTS支持当前事务,如果当前没有事务,就以非事务方式执行。
PROPAGATION_MANDATORY使用当前的事务,如果当前没有事务,就抛出异常。当业务方法被设置为PROPAGATION_MANDATORY时,它就不能被非事务的业务方法调用。如将ClassB.c() 设置为PROPAGATION_MANDATORY,如果展现层的Action直接调用c()方法,将引发一个异常。正确的情况是:
c()方法必须被另一个带事务的业务方法调用比如示例2。 PROPAGATION_MANDATORY的方法一般都是被其它业务方法间接调用的。
PROPAGATION_REQUIRES_NEW新建事务,如果当前存在事务,把当前事务挂起。
PROPAGATION_NOT_SUPPORTED以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。当方法被设置为PROPAGATION_NOT_SUPPORTED时,外层业务方法的事务会被挂起,当内部方法运行完成后,外层方法的事务重新运行。如果外层方法没有事务,直接运行,不需要做任何其它的事。
PROPAGATION_NEVER以非事务方式执行,如果当前存在事务,则抛出异常。当业务方法被设置为PROPAGATION_NEVER时,它将不能被拥有事务的其它业务方法调用。假设ClassB.c()
()设置为PROPAGATION_NEVER,当Class.a()拥有一个事务时,c()方法将抛出异常。所以PROPAGATION_NEVER方法一般是被直接调用的如示例1。
PROPAGATION_NESTED如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则执行与PROPAGATION_REQUIRED类似的操作。PROPAGATION_NESTED和PROPAGATION_REQUIRES_NEW的区别在于:PROPAGATION_REQUIRES_NEW 启动一个新的、和外层事务无关的“内部”事务。该事务拥有自己的独立隔离级别和锁,不依赖于外部事务,独立地提交和回滚。当内部事务开始执行时,外部事务 将被挂起,内务事务结束时,外部事务才继续执行。将创建一个全新的事务,它和外层事务没有任何关系.而 PROPAGATION_NESTED 将创建一个依赖于外层事务的子事务,当外层事务提交或回滚时,子事务也会连带提交和回滚。
### 三级标题:Spring事务失效的常见状态 在Spring框架中,事务生效依赖于多个条件,包括方法调用方式、异常处理、事务传播行为、数据库支持等。如果这些条件未被正确满足,事务将不会生效。以下是事务失效的常见状态及具体原因分析。 事务方法未被`public`修饰会导致事务失效。Spring事务管理基于AOP代理实现,只有`public`方法才能被代理,而`private`、`protected`或包可见的方法不会被代理,因此事务不会生效[^1]。 ```java // 示例:私有方法事务生效 @Transactional private void updateData() { // 数据库操作 } ``` 事务方法未被Spring代理也会导致事务失效。如果一个类未被Spring管理(如未使用`@Service`、`@Component`等注解),或者事务方法在同一个类中被内部调用,则Spring的AOP代理无法拦截该方法调用,导致事务失效[^1]。 ```java // 示例:内部调用导致事务失效 public void outerMethod() { innerMethod(); // 不经过代理,事务生效 } @Transactional public void innerMethod() { // 数据库操作 } ``` 事务方法中捕获异常但未抛出会导致事务回滚失败。Spring默认只在遇到未检查异常(`RuntimeException`及其子类)时回滚事务。如果在方法中捕获了异常但未重新抛出,Spring将无法感知异常,事务不会回滚[^4]。 ```java // 示例:异常被捕获导致事务不回滚 @Transactional public void performOperation() { try { aMapper.save(order); bFlowMapper.saveFlow(order); } catch (Exception e) { // 异常被捕获,事务不会回滚 } } ``` 事务方法未正确配置事务传播行为也可能导致事务失效。例如,使用`Propagation.SUPPORTS`或`Propagation.NOT_SUPPORTED`等传播行为时,事务可能不会按照预期开启或传播,导致事务失效。 ```java // 示例:错误的传播行为配置 @Transactional(propagation = Propagation.SUPPORTS) public void readData() { // 只读操作,可能不开启事务 } ``` 多线程环境下,Spring的声明式事务会失效。由于事务上下文是基于`ThreadLocal`机制存储的,每个线程拥有独立的事务上下文副本,因此新线程中的操作不会被包含在原有事务中,导致事务失效[^3]。 ```java // 示例:多线程环境下事务失效 @Transactional public void performInTransaction() { new Thread(() -> { // 该线程中的操作不在事务中 }).start(); } ``` 事务方法未被Spring管理的另一个情况是类未被正确注册为Spring Bean。例如,使用`new`关键字手动创建实例而非通过Spring注入,事务将不会生效[^2]。 ```java // 示例:手动new对象导致事务失效 MyService service = new MyService(); service.performOperation(); // 事务不会生效 ``` 数据库不支持事务也是事务失效的重要原因。例如,MySQL的MyISAM存储引擎不支持事务,即使Spring配置正确,事务也不会生效事务方法中嵌套调用其他事务方法时,若未正确配置嵌套事务或保存点,可能导致事务失效。例如,未正确使用`Propagation.NESTED`或未处理嵌套事务的异常回滚逻辑,事务可能不会按预期回滚[^5]。 ```java // 示例:嵌套事务未正确配置 @Transactional public void outerMethod() { try { nestedMethod(); // 未正确配置嵌套事务 } catch (Exception e) { // 外部事务可能不会回滚 } } @Transactional public void nestedMethod() { throw new RuntimeException("Nested exception"); } ``` 综上所述,Spring事务失效的常见状态包括:方法未被`public`修饰、内部方法调用、异常被捕获未抛出、事务传播行为配置错误、多线程环境、未被Spring管理、数据库不支持事务以及嵌套事务配置不当。开发人员应根据具体场景选择合适的解决方案,以确保事务的正确执行。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值