`

spring 异常与事务

 
阅读更多
Service层捕获异常,并抛出RuntimeException异常到Action层:

public void lock(String id) throws RuntimeException {  
    try {  
        this.loginUserDao.lock(id);  
        LoginUser user = this.loginUserDao.findById(id);  
        user.setSex("捕捉到异常后,抛出RuntimeException类型的异常");  
        this.loginUserDao.save(user);  
    } catch (Exception e) {  
        // 捕捉到异常后,抛出RuntimeException类型的异常。  
        // spring 事务只在捕足到RuntimeException异常时,才会回滚,对Exception无效  
        throw new RuntimeException(e.getMessage());  
    }  
}  




spring中事务管理配置:

<!-- 为sessionFactory定义事务管理器 -->  
<bean id="transactionManager"  
    class="org.springframework.orm.hibernate3.HibernateTransactionManager">  
    <property name="sessionFactory">  
        <ref local="sessionFactory" />  
    </property>  
</bean>  
  
<!-- 定义事务拦截器 -->  
<bean id="transactionInterceptor"  
    class="org.springframework.transaction.interceptor.TransactionInterceptor">  
    <!-- 为事务拦截器注入一个事务管理器 -->  
    <property name="transactionManager" ref="transactionManager" />  
    <property name="transactionAttributes">  
        <!-- 定义事务传播属性 PROPAGATION_REQUIRED:表示如果事务不存在,则创建一个新事务,如果存在,则加入到该事务。 -->  
        <props>  
            <prop key="save*">PROPAGATION_REQUIRED</prop>  
            <prop key="add*">PROPAGATION_REQUIRED</prop>  
            <prop key="delete*">PROPAGATION_REQUIRED</prop>  
            <prop key="update*">PROPAGATION_REQUIRED</prop>  
            <prop key="lock*">PROPAGATION_REQUIRED</prop>  
            <prop key="unLock*">PROPAGATION_REQUIRED</prop>  
            <prop key="find*">PROPAGATION_REQUIRED,readOnly</prop>  
            <prop key="list*">PROPAGATION_REQUIRED,readOnly</prop>  
            <prop key="get*">PROPAGATION_REQUIRED,readOnly</prop>  
            <prop key="*">PROPAGATION_REQUIRED,readOnly</prop>  
        </props>  
    </property>  
</bean>  
<!-- 定义拦截器要拦截的bean -->  
<bean id="autoProxy"  
    class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">  
    <property name="beanNames">  
        <list>  
            <!-- 拦截所有名字以Service结尾的bean进行代理 -->  
            <value>*Service</value>  
        </list>  
    </property>  
    <property name="interceptorNames">  
        <list>  
            <value>transactionInterceptor</value>  
        </list>  
    </property>  
</bean>  

reference:http://blog.csdn.net/greensurfer/article/details/7520742


<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
<beans>

    <bean id="propertyConfigurer"
        class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
        <property name="locations">
            <list>
                <value>classpath:jdbc.properties</value>
            </list>
        </property>
    </bean>

    <bean id="dataSource" 
        class="com.mchange.v2.c3p0.ComboPooledDataSource"
        destroy-method="close" >
        <property name="driverClass" value="${jdbc.driverClassName}" />
        <property name="jdbcUrl" value="${jdbc.url}" />
        <property name="user" value="${jdbc.username}" />
        <property name="password" value="${jdbc.password}" />
        <property name="minPoolSize" value="${jdbc.minPoolSize}" />
        <property name="maxPoolSize" value="${jdbc.maxPoolSize}" />
        <property name="initialPoolSize"
            value="${jdbc.initialPoolSize}" />
        <property name="maxIdleTime" value="${jdbc.maxIdleTime}" />
        <property name="acquireIncrement"
            value="${jdbc.acquireIncrement}" />
        <property name="maxStatements" value="${jdbc.maxStatements}" />
        <property name="idleConnectionTestPeriod"
            value="${jdbc.idleConnectionTestPeriod}" />
        <property name="acquireRetryAttempts"
            value="${jdbc.acquireRetryAttempts}" />
        <property name="acquireRetryDelay"
            value="${jdbc.acquireRetryDelay}" />
        <property name="breakAfterAcquireFailure"
            value="${jdbc.breakAfterAcquireFailure}" />
        <property name="maxConnectionAge"
            value="${jdbc.maxConnectionAge}" />
    </bean>

    <bean id="sqlMapClient"
        class="org.springframework.orm.ibatis.SqlMapClientFactoryBean">
        <property name="dataSource" ref="dataSource" />
        <property name="configLocation">
            <value>classpath:conf/ibatis/sql-map-config.xml</value>
        </property>
    </bean>

    <bean id="transactionManager"
        class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource">
            <ref bean="dataSource" />
        </property>
    </bean>

    <bean id="transactionInterceptor"
        class="org.springframework.transaction.interceptor.TransactionInterceptor">
        <property name="transactionManager" ref="transactionManager" />
        <property name="transactionAttributes">
            <props>
                <prop key="pre">PROPAGATION_REQUIRES_NEW,-Exception</prop>
                <prop key="*">PROPAGATION_REQUIRED,-Exception</prop>
                                            </props>
        </property>
    </bean>
    <bean
        class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
        <property name="proxyTargetClass" value="true" />
        <property name="beanNames">
            <value>*Service</value>
        </property>
        <property name="interceptorNames">
            <list>
                <value>transactionInterceptor</value>
            </list>
        </property>
    </bean>
    <bean
        class="org.springframework.transaction.interceptor.TransactionAttributeSourceAdvisor">
        <property name="transactionInterceptor"
            ref="transactionInterceptor" />
    </bean>
    
</beans>




异常捕获不抛出,Spring事务无法回滚

默认spring只在发生未被捕获的runtimeexcetpion时才回滚。

最笨的办法:代码级控制:TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();

为何在aop  advitor中配置rollba-for=“java.lang.Exception”异常时不回滚呢?

问题已解决:

原理:spring aop  异常捕获原理:被拦截的方法需显式抛出异常,并不能经任何处理,这样aop代理才能捕获到方法的异常,才能进行回滚,默认情况下aop只捕获runtimeexception的异常,但可以通过
<tx:method name="upd*" propagation="REQUIRED" rollback-for="java.lang.Exception"/>
配置来捕获特定的异常并回滚

换句话说在service的方法中不使用try catch 或者在catch中最后加上throw new runtimeexcetpion(),这样程序异常时才能被aop捕获进而回滚

解决方案:
方案1.例如service层处理事务,那么service中的方法中不做异常捕获,或者在catch语句中最后增加throw new RuntimeException()语句,以便让aop捕获异常再去回滚,并且在service上层(webservice客户端,view层action)要继续捕获这个异常并处理

<bean id="transactionManager"
  class="org.springframework.orm.hibernate3.HibernateTransactionManager">
  <property name="sessionFactory" ref="sessionFactory" />
 </bean>
 <tx:advice id="txAdvice" transaction-manager="transactionManager">
  <tx:attributes>
   <tx:method name="add*" propagation="REQUIRED" />
   <tx:method name="upd*" propagation="REQUIRED" rollback-for="java.lang.Exception"/>
   <tx:method name="del*" propagation="REQUIRED" />
   <tx:method name="*" propagation="SUPPORTS" />
  </tx:attributes>
 </tx:advice>
 <aop:config>
  <aop:pointcut id="canyin" expression="execution(* com.laphone.base.baseservice.*.*(..)) ||execution(* com.laphone.canyin.*.service.*.*(..)) || execution(* com.laphone.canyin.*.*.service.*.*(..))"/>
  <aop:advisor advice-ref="txAdvice" pointcut-ref="canyin" />
 </aop:config>


*******************

Spring事务处理的两种方式

spring事务管理:
可以通过两种方式实现,一是用AOP来控制事务:

<!-- 配置事务管理器 --> 
<bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager"> 
<property name="sessionFactory"> 
<ref local="sessionFactory"/> 
</property> 
</bean>
<!-- 配置事务特性 --> 
<tx:advice id="txAdvice" transaction-manager="transactionManager"> 
<tx:attributes> 
<tx:method name="*" propagation="REQUIRED"/> 
<!-- 
<tx:method name="add*" propagation="REQUIRED"/> 
<tx:method name="del*" propagation="REQUIRED"/> 
<tx:method name="update*" propagation="REQUIRED"/> 
<tx:method name="deploy*" propagation="REQUIRED"/> 
<tx:method name="submit*" propagation="REQUIRED"/> 
<tx:method name="*" read-only="true"/> 
--> 
</tx:attributes> 
</tx:advice>
<!-- 配置哪些类的方法进行事务管理 --> 
<aop:config> 
<aop:pointcut id="allManagerMethod" expression="execution (* com.bjsxt.oa.managers.*.*(..))"/> 
<aop:advisor advice-ref="txAdvice" pointcut-ref="allManagerMethod"/> 
</aop:config>



二是用事务拦截器的方式来控制事务:

<!-- Transaction manager for a single Hibernate SessionFactory (alternative to JTA) --> 
<bean id="myTransactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager"> 
<property name="sessionFactory"> 
<ref local="mySessionFactory" /> 
</property> 
</bean> 
<!-- 配置事务管理 --> 
<bean id="userService" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean"> 
<property name="transactionManager"> 
<ref local="myTransactionManager" /> 
</property> 
<property name="target"> 
<ref local="loginTarget" /> 
</property> 
<property name="transactionAttributes"> 
<props> 
<prop key="save*">PROPAGATION_REQUIRED</prop> 
</props> 
</property> 
</bean>
<!-- OrderTarget primary business object implementation --> 
<bean id="loginTarget" class="com.test.spring.UserServiceImpl"> 
<property name="userDAOIF"> 
<ref local="userDAO" /> 
</property> 
</bean>
<!-- DAO object: Hibernate implementation --> 
<bean id="userDAO" class="com.test.hibernate.UserDAOImpl"> 
<property name="sessionFactory"> 
<ref local="mySessionFactory" /> 
</property> 
</bean>




*******************

Spring AOP声明式事务异常回滚

Spring的AOP事务管理默认是针对unchecked exception回滚。

也就是默认对RuntimeException()异常极其子类进行事务回滚。

Exception作为基类,下面还分checked exception和unchecked exception。如果客户端可以通过其他的方法恢复异常,那么这种异

常就是checked exception;如果客户端对出现的这种异常无能为力,那么这种异常就是Unchecked exception;简单来说,继承于

RuntimeException的都是unchecked exception。

Error:
1.总是不可控制的(unchecked)
2.经常用来用于表示系统错误或低层资源的错误
3.如何可能的话,应该在系统级被捕捉

Exception:
1.可以是可被控制(checked) 或不可控制的(unchecked)
2.表示一个由程序员导致的错误
3.应该在应用程序级被处理

Java 中定义了两类异常:
1) Checked exception: 这类异常都是Exception的子类。异常的向上抛出机制进行处理,假如子类可能产生A异常,那么在父类中

也必须throws A异常。可能导致的问题:代码效率低,耦合度过高。
2) Unchecked exception: 这类异常都是RuntimeException的子类,虽然RuntimeException同样也是Exception的子类,但是它们是

非凡的,它们不能通过client code来试图解决,所以称为Unchecked exception 。

解决办法:

1.在针对事务的类中抛出RuntimeException异常,而不是抛出Exception。

2.在txAdive中增加rollback-for,里面写自己的exception,例如自己写的exception为

com.cn.untils.exception.***Exception

<tx:advice id="txAdvice" transaction-manager="transactionManager">
  <tx:attributes>
    <tx:method name="*" rollback-for="com.cn.untils.exception.***Exception"/>
  </tx:attributes>
</tx:advice>


或者

定义不会滚的异常
<tx:advice id="txAdvice">
   <tx:attributes>
      <tx:method name="update*" no-rollback-for="IOException"/>
      <tx:method name="*"/>
   </tx:attributes>
</tx:advice>


Spring transaction事务之roll back回滚

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

试验过程:
         定义一个service方法如下:

public SMSTiming createSMSTiming(SMSTiming smsTiming){
                   SMSTiming s= this.getSmsTimingDAO().createSMSTiming(smsTiming);
                   return s;
         }


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


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

测试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框架的事务基础架构代码将默认地 只 在抛出运行时和unchecked exceptions时才标识事务回滚。 也就是说,当抛出一个 RuntimeException 或其子类例的实例时。(Errors 也一样 - 默认地 - 标识事务回滚。)从事务方法中抛出的Checked exceptions将 不 被标识进行事务回滚

SSH整合,spring事务管理不回滚问题
http://blog.csdn.net/greensurfer/article/details/7520742
http://www.iteye.com/topic/289014
http://hi.baidu.com/iduany/item/20f8f8ed24e1dec5bbf37df7
http://www.iteye.com/topic/9842
分享到:
评论

相关推荐

    Spring事务管理Demo

    2. **声明式事务管理**:这是Spring最常用的方式,通过在配置文件或者使用`@Transactional`注解来定义事务边界,使得事务管理与业务逻辑分离,降低了代码的耦合度。`@Transactional`注解可以应用于方法级别,表示该...

    Spring事务流程图

    若出现异常,Spring会自动回滚事务,以保证数据的一致性。 4. **事务隔离**:Spring支持多种事务隔离级别,如READ_UNCOMMITTED、READ_COMMITTED、REPEATABLE_READ、SERIALIZABLE,不同的隔离级别能防止特定类型的...

    Spring事务与Java事务比较

    此外,Spring 还提供了事务回滚规则,允许基于异常类型或异常实例来决定是否回滚事务,增强了事务处理的灵活性。 Spring AOP 用于实现事务管理服务,它通过代理模式在方法调用前后插入事务处理代码,无需修改原有...

    spring 简单实例 事务回滚

    这会告诉Spring在调用此方法时启动一个新的事务,并在方法正常结束时提交事务,或者在遇到异常时回滚事务。 4. 异常处理:为了触发事务回滚,方法内通常会抛出未检查异常(继承自`RuntimeException`的异常)或显式...

    Spring声明式事务处理

    在Spring中,事务管理分为编程式和声明式两种方式,而声明式事务处理则是通过配置来控制事务的行为,使得代码与事务逻辑解耦,提高了代码的可读性和可维护性。 首先,我们要理解什么是事务。事务是数据库操作的一组...

    spring声明式事务处理demo

    同时,需要配置数据源(DataSource)和事务管理器(如`DataSourceTransactionManager`或`JpaTransactionManager`),以便Spring知道如何与数据库交互并管理事务。 ```xml &lt;bean id="dataSource" class="org.spring...

    Spring中事务的传播属性详解

    如果当前不存在事务,那么行为与`PROPAGATION_REQUIRED`相同。嵌套事务允许独立于外部事务的回滚,但在外部事务回滚时,嵌套事务也会回滚。 #### 五、总结 通过上述分析,我们可以看出Spring中的事务传播行为提供...

    spring-tx事务管理实例

    本实例将深入探讨Spring事务管理的实现与应用。 首先,Spring事务管理分为编程式事务管理和声明式事务管理两种方式。编程式事务管理是通过调用TransactionTemplate或直接使用PlatformTransactionManager接口来控制...

    Spring AOP配置事务方法

    在上面的配置文件中,我们可以看到 `&lt;tx:advice&gt;` 元素用于定义一个名为 "sgis.sdk.txAdvice" 的事务特性,该特性将所有以 "add*"、"delete*"、"update*" 开头的方法纳入事务管理中,并在出现异常时回滚事务。...

    spring编程式事务实现

    默认情况下,如果在事务回调中抛出未检查异常(继承自`RuntimeException`)或`Error`,Spring会自动回滚事务。对于已检查异常,需要显式设置`rollbackFor`属性,或在`TransactionCallback`中调用`TransactionStatus...

    spring boot注解事务+多线程

    在Spring Boot应用中,事务管理和多线程是两个非常关键的特性,特别是在处理复杂的业务逻辑时。本示例将深入探讨如何使用注解来实现事务控制以及如何在Spring Boot中运用多线程。 首先,让我们关注"注解事务"。在...

    spring声明事务的配置

    总的来说,Spring声明式事务管理提供了一种强大且灵活的方式来控制事务的边界,使得事务管理与业务逻辑分离,提高了代码的可维护性和测试性。通过合理地配置事务属性,可以确保应用程序的数据一致性,同时提高性能。

    spring事务操作试验

    文件名如"spring-jdbc-tran1"、"spring-jdbc-tran2"和"spring-jdbc-tran3"暗示了实验可能涉及Spring与JDBC的事务交互。在Spring中,DataSourceTransactionManager是用于JDBC事务管理的默认实现。使用它,你可以控制...

    spring学习事务源码

    在Spring框架中,事务管理是核心特性之一,它使得开发者能够在多操作数据库时保持数据的一致性和完整性。本文将深入探讨Spring事务管理的源码,理解其背后的实现机制。 首先,Spring事务管理有两种主要模式:编程式...

    Spring事务原理、Spring事务配置的五种方式

    如果当前没有事务,则进行与PROPAGATION_REQUIRED类似的操作。 Spring事务管理创造性的解决了很多以前要用重量级的应用服务器才能解决的事务问题,那么其实现原理一定很深奥吧?可是如果读者仔细研究了Spring事务...

    Spring 框架的事务管理及应用

    ### Spring框架的事务管理及应用 #### Spring框架概述 Spring框架是一个开源项目,最早出现在2003年2月,其起源可以追溯到Rod Johnson在2002年末出版的书籍《Expert One-on-One J2EE Design and Development》中的...

    spring声明式事务管理配置方式

    - 默认情况下,如果@Transactional标记的方法中抛出未检查异常(继承自RuntimeException的异常)或Error,Spring会自动回滚事务。如果抛出受检异常(非RuntimeException),则不会自动回滚,除非你在@Transactional...

    spring编程式事务与声明式事务详解

    Spring 编程式事务与声明式事务详解 本文将详细解释 Spring 的编程式事务管理及声明式事务管理,帮助读者理清思路。 事务管理的重要性 事务管理对于企业应用至关重要。它保证了用户的每一次操作都是可靠的,即便...

    Spring事务管理失效原因汇总

    在讨论了代理模式、异常分类、方法权限后,文章还提到了Spring事务管理中事务的传播机制和隔离机制。事务的传播机制定义了事务的行为,例如是否在当前事务中执行或者创建一个新的事务。隔离机制定义了事务之间的隔离...

    Spring 事务简单完整例子

    在上述例子中,`createUser`方法被标记为`@Transactional`,这意味着如果方法内部抛出未检查异常(继承自`RuntimeException`的异常)或者受检异常(如`IOException`),Spring会自动回滚事务。如果没有异常,事务将...

Global site tag (gtag.js) - Google Analytics