service中配置的事务回滚不起作用

这两天一直在研究一个东西,关于事务回滚的,因为我突然发现我们项目竟然不支持,不支持,但是我们整个事务的配置文件都是有的。

关于事务配置,我就不再多阐述了,可以参考这篇文章: 事务回滚配置

下面说我遇到的问题吧,就是所有的配置都完成了,但就是不起作用,抛出了RuntimeException就是不会滚,数据库操作该执行还是执行了。最后才想到会不会是数据库表引擎的问题,立马去看,果然,表引擎都是myisam,我的天,把引擎改一下,立马好了。

下面总结一下,在确认配置文件都配置好,所有工作都无误的情况下还是不支持事务时的几个检查方面:

使用@Transactional注解的回滚方式的检查方面

1、看方法是否是public的,注解方式默认只在public修饰的方法上起作用,protected、private 或者 default 修饰的方法上使用@Transactional时不会报错,但是事务设置不起作用。

2、检查是不是同一个类中方法的调用。(比如同一个方法中存在A和B两个方法,A方法去调用B方法)

基于spring aop的配置回滚方式的检查方面

1、配置文件中的aop相关配置,看expression配置的路径是否可以扫描到你的方法。

<aop:config>
        <aop:pointcut id="transactionPointcut" expression="execution(* com.test.service.impl..*.*(..))" />
        <aop:advisor pointcut-ref="transactionPointcut" advice-ref="transactionAdvice" />
</aop:config>

上面代码中我配置的是 扫描com.test.service.impl 包及其子包中的所有的方法。

顺便给出execution表达式常见的相关配置说明:

execution(public * *(..))                      任意的公共方法

execution(* set*(..))                          任何以set开头的方法

execution( * com.test.service.impl.*.*(..))       com.test.service.impl包下的任意方法

execution( * com.test.service.impl..*.*(..))      com.test.service.impl包及其子包下的任意方法

下面是以上两种配置方式都可能出现不回滚的检查方面:

1、数据库引擎要支持事务,如果是MySQL,注意表要使用支持事务的引擎,比如innodb,如果是myisam,事务配置是不起作用的。

2、看service是否进行了try...catch...但是没有在catch块中继续抛出异常。

以下代码进行了try...catch...将异常捕获了,所以spring没法识别你的异常,当然也不会进行回滚。

public void test () { 
    try{
        insert(a);
        delete(b)
    } catch {
        System.out.println("不会回滚!!!");
    }
}

    正解如下,进行了try...catch...之后再catch块中继续进行异常的抛出,这样就可以实现回滚。

public void test () { 
    try{
        insert(a);
        delete(b)
    } catch {       
         throw new RuntimeException("操作失败!!!");
    }
}

好了,到此结束,自己问题也解决了,希望简单的总结能帮到一个两个的同行!

此文为原创,转载请注明出处,谢谢!

 

 

 

在 Java 应用中,特别是在使用 Spring MyBatis 等框架进行数据库操作时,事务回滚不完全的问题较为常见。这类问题通常表现为:在方法抛出异常后,事务并未如预期那样回滚,导致数据库状态出现不一致的情况。 ### 1. 常见原因 #### (1)事务仅对运行时异常(unchecked exceptions)生效 Spring 的默认行为是只对 `RuntimeException` 及其子类进行事务回滚。如果代码中抛出的是受检异常(checked exceptions),例如 `IOException` 或自定义的 `Exception` 子类,而没有明确配置事务管理器处理这些异常,则事务不会自动回滚 [^4]。 #### (2)注解未正确使用或作用范围受限 - **@Transaction** 注解只能用于 public 方法上,否则 Spring AOP 无法正确代理该方法并开启事务。 - 如果一个类中的某个方法调用了另一个带有 `@Transactional` 注解方法,并且这两个方法处于同一个类中(即 self-invocation 自调用),则事务可能不会生效。这是由于 Spring 使用动态代理机制实现声明式事务,自调用不会经过代理对象 [^3]。 #### (3)事务传播行为配置不当 Spring 提供了多种事务传播行为(propagation behavior),例如: - `REQUIRED`(默认):如果当前存在事务,则入;否则新建事务; - `REQUIRES_NEW`:无论当前是否有事务,都新建事务并挂起现有事务; - `SUPPORTS`:支持当前事务,若无事务则以非事务方式执行等。 如果多个服务之间通过不同的传播行为组合调用,可能导致某些操作不在事务控制范围内,从而引发部分回滚失败 [^1]。 #### (4)手动提交/回滚与自动事务冲突 在使用 MyBatis 时,如果没有正确关闭自动提交(autoCommit),或者在事务中混合使用了手动提交 Spring 的声明式事务管理,也可能导致事务逻辑混乱、回滚不彻底 [^1]。 #### (5)多数据源或分布式事务未正确配置 当应用涉及多个数据库连接池(如多租户系统或多数据源架构)时,若未启用 JTA(Java Transaction API)或 XA 协议支持,Spring 默认的本地事务管理将无法保证跨资源的一致性,进而造成事务回滚不完整 [^1]。 --- ### 2. 解决方案 #### (1)配置事务回滚规则 可以通过在 `@Transactional` 注解中指定 `rollbackFor` 属性来明确哪些异常类型应触发回滚。例如: ```java @Transactional(rollbackFor = Exception.class) public void someMethod() throws Exception { // 数据库操作 } ``` 这样即使抛出的是 checked exception,也能触发事务回滚 [^4]。 #### (2)避免自调用问题 解决自调用导致事务失效的方式有以下几种: - 将需要事务方法移到另一个 bean 中,确保调用路径经过代理; - 启用 AspectJ 编译时织入(compile-time weaving)替代默认的 Spring AOP 运行时代理; - 使用 `AopContext.currentProxy()` 获取当前代理对象并显式调用事务方法 [^3]。 #### (3)合理设置事务传播行为 根据业务需求选择合适的传播行为。例如,在嵌套调用中希望每个子操作独立事务,可以使用 `REQUIRES_NEW`;而在单个业务流程中保持统一事务上下文,可采用默认的 `REQUIRED`。 #### (4)统一事务边界控制 建议将事务控制粒度放在 service 层而非 controller 层,避免在 service 内部频繁捕获异常并继续执行后续逻辑,这会破坏事务一致性。对于日志记录等辅助操作,可考虑将其移至事务外部或使用异步方式处理 [^4]。 #### (5)启用分布式事务支持 对于多数据源场景,需引入 JTA 实现(如 Atomikos、Bitronix 或 WebLogic/JBoss 提供的实现),并通过配置 `JtaTransactionManager` 来替代默认的 `DataSourceTransactionManager`,从而实现全局事务协调 。 --- ### 3. 最佳实践建议 - **始终测试事务边界**:编写单元测试验证事务是否按预期回滚; - **谨慎使用 try-catch**:在事务方法内部捕获异常后务必重新抛出或主动标记事务为 rollback; - **日志与事务分离**:尽量避免在同一事务中执行日志写入等非关键操作; - **监控事务状态**:利用 Spring 提供的 `TransactionSynchronizationManager` 监控当前线程的事务状态。 ---
评论 2
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值