Spring transaction事务之roll back回滚: rollback-for

本文通过六个具体的测试案例,详细探讨了Spring框架中事务回滚的机制,特别是针对不同类型的异常(如运行时异常和受检异常)以及如何通过配置rollback-for属性来控制哪些异常会导致事务回滚。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

试验方法:

         写一个单元测试,调用一个service层方法(发生对数据库进行写操作的方法–insert、update、delete)即可.

  applicationContext.xml 样子(如何设置rollback-for)

  1. <!– 
  2.         spring事务管理 方法一–>  
  3.     <bean id="transactionManager"  
  4.         class="org.springframework.jdbc.datasource.DataSourceTransactionManager">  
  5.         <property name="dataSource" ref="dataSource" />  
  6.     </bean>  
  7.     <aop:config>  
  8.         <aop:pointcut id="serviceOperation" expression="execution(*  
  9.         com.*.service.*.*(..))" />  
  10.         <aop:advisor pointcut-ref="serviceOperation" advice-ref="txAdvice" />  
  11.     </aop:config>  
  12.   
  13.     <tx:advice id="txAdvice" transaction-manager="transactionManager">  
  14.         <tx:attributes>  
  15.             <tx:method name="insert*" rollback-for="Exception" />  
  16.             <tx:method name="save*" rollback-for="Exception" />  
  17.             <tx:method name="update*" rollback-for="Exception" />  
  18.             <tx:method name="delete*" rollback-for="Exception" />  
  19.             <tx:method name="*" read-only="true" rollback-for="Exception" />  
  20.         </tx:attributes>  
  21.     </tx:advice>  


试验过程:

         定义一个service方法如下:

         public SMSTiming createSMSTiming(SMSTiming smsTiming){

                   SMSTiming s= this.getSmsTimingDAO().createSMSTiming(smsTiming);

                   return s;

         }

 

         定义二个异常(先默认配置TestException为Spring事务回滚异常):

            publicclass MyTestException extends Exception

            publicclass TestException extends Exception

 

    nbsp;     注意看下:每次这个方法的不同处(抛出的异常不同)。

 

测试1:

public SMSTiming createSMSTiming(SMSTiming smsTiming){

       SMSTiming s= this.getSmsTimingDAO().createSMSTiming(smsTiming);

       int i = 4/0; //人为产生异常(实际这里抛出了ArithmeticException运行异常)

       return s;

    }

测试1结果:会事务回滚—-数据库中未插入新数据。

 

 

测试2:

        public SMSTiming createSMSTiming(SMSTiming smsTiming) throws Exception{//受检异常(非运行异常)必须抛出

       SMSTiming s= this.getSmsTimingDAO().createSMSTiming(smsTiming);

       try{

           int i = 4/0; //人为产生异常

       }catch(Exception e){

           thrownew Exception ("");//抛出Exception异常

       }

       return s;

    }

测试2结果:不会事务回滚—-数据库中插入新数据。

 

        

测试3:

            public SMSTiming createSMSTiming(SMSTiming smsTiming) throws RuntimeException{//运行异常(非受检异常)可以不抛出

       SMSTiming s= this.getSmsTimingDAO().createSMSTiming(smsTiming);

       try{

           int i = 4/0; //人为产生异常

       }catch(Exception e){

           thrownewRuntimeException("");//抛出RuntimeException异常

       }

       return s;

    }

测试3结果:会事务回滚—-数据库中未插入新数据

 

测试4:

        public SMSTiming createSMSTiming(SMSTiming smsTiming) throws TestException{//受检异常(非运行异常)必须抛出

       SMSTiming s= this.getSmsTimingDAO().createSMSTiming(smsTiming);

       try{

           int i = 4/0; //人为产生异常

       }catch(Exception e){

           thrownewTestException("");//抛出TestException异常

       }

       return s;

    }

测试4结果:会事务回滚—-数据库中未插入新数据。

 

测试5:

    public SMSTiming createSMSTiming(SMSTiming smsTiming) throws MyTestException{//受检异常(非运行异常)必须抛出

       SMSTiming s= this.getSmsTimingDAO().createSMSTiming(smsTiming);

       try{

           int i = 4/0; //人为产生异常

       }catch(Exception e){

           thrownewMyTestException("");//抛出MyTestException异常

       }

       return s;

    }

 测试5结果:不会事务回滚—-数据库中插入新数据。

 

测试6:

    public SMSTiming createSMSTiming(SMSTiming smsTiming) throws MyTestException{//受检异常(非运行异常)必须抛出 (注意:此时spring指定配置此异常回滚)

       SMSTiming s= this.getSmsTimingDAO().createSMSTiming(smsTiming);

       try{

           int i = 4/0; //人为产生异常

       }catch(Exception e){

           thrownewMyTestException("");//抛出MyTestException异常

       }

       return s;

    }

 测试6结果:会事务回滚—-数据库中未插入新数据。

 

 

试验总结:

测试1、测试3、测试4、测试6会进行事务回滚;测试2、测试5不会进行事务回滚。

 

为什么会这样?因为是异常的类型(受检异常、运行时异常)不同或使用了Spring的rollback-for配置。

 

测试1和测试3是因为抛出了运行时异常,会事务回滚。

 

测试4和测试5、测试6分别抛出受检异常TestException、MyTestException,那为什么测试4和测试6会事务回滚呢?

因为是我们在Spring事务配置中指定了此异常(指定rollback-for)。



又一篇文章:

昨天同事说Spring的Transactional必须添加rollbackFor = Exception.class,否则事务不会回滚。但我原来试过,抛出RuntimeException时是会回滚的。于是查看Spring的Transactional的API文档,发现下面这段:

If no rules are relevant to the exception, it will be treated like DefaultTransactionAttribute (rolling back on runtime exceptions).

后面又试了下发现,如果不添加rollbackFor等属性,Spring碰到Unchecked Exceptions都会回滚,不仅是RuntimeException,也包括Error。


转载地址

### 解析 `javax.persistence.RollbackException` 和 `PersistenceException` 当遇到 `javax.persistence.RollbackException: Transaction marked as rollbackOnly` 错误时,这表明当前事务已被标记为仅能回滚而无法提交。此情况通常发生在违反业务逻辑、数据库约束或发生其他异常的情况下[^1]。 对于 `javax.persistence.PersistenceException` 类型的异常,这类问题可能源于多种原因,比如尝试保存已分离实体(detached entity),或是由于底层 JDBC 连接出现问题等[^2]。 #### 原因分析 - **未满足的约束条件**:如果操作违背了外键或其他类型的完整性约束,则会触发此类异常。 - **并发冲突**:高并发场景下可能出现乐观锁版本号不匹配等问题。 - **资源不可用**:如网络中断导致的数据源连接丢失也会引发相应错误。 - **编程失误**:不当管理持久化上下文生命周期可能导致对象状态混乱;另外,在需要显式开启新事务的地方忘记声明 @Transactional 注解也可能造成影响[^3]。 #### 处理方法 为了妥善应对上述挑战并修复 Oracle JPA 中发生的事务回滚失败现象: 1. **增强异常捕获** 确保所有涉及数据访问层的方法都具备完善的 try-catch 结构,并针对不同种类的具体异常采取恰当措施。例如,可以捕捉到具体的 Hibernate 异常来获取更多诊断信息。 ```java try { // 数据库交互代码... } catch (EntityExistsException e) { logger.error("Duplicate entry detected.", e); throw new CustomBusinessException("Record already exists."); } ``` 2. **优化事务配置** 检查 Spring Boot 应用程序中的事务设置是否合理,特别是传播行为(propagation behavior),以及超时时间(timeout period)等方面。适当调整这些参数有助于提高系统的稳定性和响应速度。 ```properties spring.jpa.properties.hibernate.transaction.flush_before_completion=true spring.jpa.properties.hibernate.current_session_context_class=thread ``` 3. **审查 SQL 日志** 启用详细的SQL语句打印功能可以帮助定位潜在性能瓶颈或者语法上的缺陷。通过观察实际执行路径,更容易发现隐藏的问题所在。 ```yaml logging.level.org.hibernate.SQL=DEBUG logging.level.org.hibernate.type.descriptor.sql.BasicBinder=TRACE ``` 4. **验证隔离级别** 确认所使用的默认事务隔离等级适合具体应用场景的要求。有时较低级别的读取一致性虽然提高了吞吐量却牺牲了一致性保障,反之亦然。因此有必要权衡利弊做出最佳选择[^5]。 ```sql SELECT @@session.tx_isolation; SET SESSION TRANSACTION ISOLATION LEVEL SERIALIZABLE; ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值