Spring嵌套事务几种情形

为了方便,使用伪代码表示:)

1、同一个类,两个方法上都有事务

class A {
    @Transactional
    function T1() {
        curd 操作1
        T2()
    }

    @Transactional
    function T2() {
        curd 操作2
        抛异常
    }
}

结果:操作1和操作2都回滚

2、同一个类,被调用的方法上才有事务

class A {
    function T1() {
        curd 操作1
        T2()
    }

    @Transactional
    function T2() {
        curd 操作2
        抛异常
    }
}

结果:操作1和操作2都不回滚

3、同一个类,主方法上才有事务

class A {
    @Transactional
    function T1() {
        curd 操作1
        T2()
    }

    function T2() {
        curd 操作2
        抛异常
    }
}

结果:操作1和操作2都回滚

 

4、不同类,两个方法上都有事务

class A {
    @Transactional
    function T1() {
        curd 操作1
        B.T2()
    }
}

class B {
    @Transactional
    function T2() {
        curd 操作2
        抛异常
    }
}

结果:操作1和操作2都回滚

 

5、不同类,被调用的方法上才有事务

class A {
    function T1() {
        curd 操作1
        B.T2()
    }
}

class B {
    @Transactional
    function T2() {
        curd 操作2
        抛异常
    }
}

结果:只有操作2回滚

 

几篇关于Spring事务,动态代理的好文章:

Spring 容器AOP的实现原理动态代理 https://www.cnblogs.com/cfas/p/9307546.html 

使用动态代理实现对事务的控制 https://blog.youkuaiyun.com/a2231476020/article/details/93233115

https://www.cnblogs.com/superjt/p/4275293.html

https://blog.youkuaiyun.com/levae1024/article/details/82998386

### Spring 事务失效的常见场景及解决方案 Spring 事务失效是开发中常见的问题,其主要原因是配置不当或使用方式错误。以下是事务失效的一些常见场景及其解决方案: #### 1. 自调用问题(直接内部调用) 当一个类中的方法A通过事务注解`@Transactional`声明了事务支持,但在同一个类中另一个方法B直接调用方法A时,事务并不会生效。这是因为Spring AOP代理机制只对代理对象外部的调用有效,而自调用不会触发代理逻辑[^2]。 **解决方案**: - 将方法A和方法B拆分到不同的类中。 - 使用`ApplicationContext`获取当前类的代理实例,通过代理实例调用方法A。 ```java @Service public class MyService { @Autowired private ApplicationContext applicationContext; public void methodB() { MyService proxy = (MyService) applicationContext.getBean(MyService.class); proxy.methodA(); // 通过代理调用确保事务生效 } @Transactional public void methodA() { // 事务逻辑 } } ``` --- #### 2. 非事务方法调用事务方法 如果一个非事务方法调用了事务方法,但事务方法的事务上下文并未传递给调用方,则事务可能失效[^3]。 **解决方案**: - 确保事务方法的调用方也具有事务支持。 - 或者将事务方法抽取到独立的服务类中,确保其被正确代理。 --- #### 3. 异常类型不匹配 Spring 默认只会捕获`RuntimeException`及其子类来触发事务回滚。如果业务代码抛出的是`Checked Exception`(如`Exception`),则事务不会自动回滚[^4]。 **解决方案**: - 在`@Transactional`注解中显式指定需要回滚的异常类型。 ```java @Transactional(rollbackFor = Exception.class) public void myMethod() throws Exception { // 可能抛出 Exception 的业务逻辑 } ``` --- #### 4. 数据库连接未启用事务支持 某些数据库驱动或配置可能导致事务无法正常工作。例如,数据库连接池未正确配置为支持事务,或者数据库本身未开启事务支持。 **解决方案**: - 确保数据库连接池和驱动程序支持事务。 - 检查数据库是否启用了事务支持(如MySQL的InnoDB存储引擎)。 --- #### 5. 事务传播行为不当 Spring 提供了多种事务传播行为(如`REQUIRED`、`REQUIRES_NEW`等)。如果传播行为配置不当,可能会导致事务失效或不符合预期。 **解决方案**: - 根据业务需求选择正确的事务传播行为。 - 确保嵌套事务的传播行为与主事务兼容。 ```java @Transactional(propagation = Propagation.REQUIRES_NEW) public void nestedMethod() { // 嵌套事务逻辑 } ``` --- #### 6. 缺少事务管理器配置 如果没有正确配置事务管理器(如`DataSourceTransactionManager`),Spring 事务将无法正常工作。 **解决方案**: - 确保在Spring配置文件或Java配置类中正确定义了事务管理器。 ```java @Configuration @EnableTransactionManagement public class TransactionConfig { @Bean public DataSourceTransactionManager transactionManager(DataSource dataSource) { return new DataSourceTransactionManager(dataSource); } } ``` --- #### 7. 手动回滚未正确实现 在某些情况下,开发者可能需要手动回滚事务。如果手动回滚逻辑实现不当,可能会导致事务失效。 **解决方案**: - 在`catch`块中抛出`RuntimeException`。 - 或者使用`TransactionAspectSupport.currentTransactionStatus().setRollbackOnly()`手动标记事务回滚。 ```java try { // 业务逻辑 } catch (Exception e) { TransactionAspectSupport.currentTransactionStatus().setRollbackOnly(); } ``` --- ### 总结 Spring 事务失效的原因主要包括自调用问题、异常类型不匹配、事务传播行为不当、事务管理器配置缺失等。通过合理配置事务注解、调整传播行为以及正确处理异常,可以有效避免事务失效的问题。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值