2013-05-07 58 views
4

我正在使用spring 3.0.5和hibernate 3.6。在我的项目中有一个场景,我必须回滚事件抛出或发生错误的任何异常。这是示例代码,一切工作正常,除了交易没有得到回滚,当我抛出一个异常,但如果有任何异常抛出如mysql.IntegrityConstraintException然后事务回滚,为什么这不会发生在我的情况?如何在抛出异常时回滚Spring事务

的applicationContext.xml

<bean id="propertyConfigurer" 
      class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"> 
     <property name="location" value="classpath:database.properties"/> 
    </bean> 
     <bean id="myDataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close"> 
      <property name="driverClassName" value="${jdbc.driverClassName}" /> 
      <property name="url" value="${jdbc.url}" /> 
      <property name="username" value="${jdbc.username}" /> 
      <property name="password" value="${jdbc.password}" /> 

     </bean> 

<bean id="sessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean"> 
<property name="dataSource" ref="myDataSource" /> 
    <property name="packagesToScan" value="com.alw.imps"/> 
    <property name="configLocation">  
     <value> 
      classpath:hibernate.cfg.xml 
     </value> 
    </property> 
    </bean> 

    <bean id="stateDao" class="com.alw.imps.dao.StateDaoImpl"> 
    <property name="sessionFactory" ref="sessionFactory"></property> 
    </bean> 


     <bean id="stateService" class="com.alw.imps.services.StateService"> 
     <property name="stateDao" ref="stateDao"></property> 
     <property name="cityDao" ref="cityDao"></property> 
     <property name="customerDao" ref="customerDao"></property> 
     </bean> 

     <bean id="customerDao" class="com.alw.imps.dao.CustomerDaoImpl"> 
     <property name="sessionFactory" ref="sessionFactory"></property> 
     </bean> 

      <bean id="cityDao" class="com.alw.imps.dao.CityDaoImpl"> 
       <property name="sessionFactory" ref="sessionFactory"></property> 
      </bean> 





<tx:annotation-driven transaction-manager="transactionManager" /> 

<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="*" propagation="REQUIRED" /> 
</tx:attributes> 
</tx:advice> 

服务类的StateService

@Transactional(rollbackFor={Exception.class}) 
public class StateService { 

    private StateDaoImpl stateDao; 
    private CityDao cityDao; 
    private CustomerDao customerDao; 

    public void setCustomerDao(CustomerDao customerDao) { 
    this.customerDao = customerDao; 
    } 

    public void setStateDao(StateDaoImpl stateDao) { 
    this.stateDao = stateDao; 
    } 

    public CityDao getCityDao() { 
    return cityDao; 
    } 

    public void setCityDao(CityDao cityDao) { 
    this.cityDao = cityDao; 
    } 

    public void addState() { 
    try { 
     State state=new State(); 
     state.setStateName("Delhi"); 
     stateDao.create(state); 
     addCity(); 
     addCustomer(); 
    } catch(Exception e) { 
     e.printStackTrace(); 
    } 
    } 

    public void addCity() throws Exception { 
    City city=new City(); 
    city.setCiytName("Delhi"); 
    city.setStateId(1); 
    cityDao.create(city); 
    } 

    public void addCustomer() throws Exception { 
    throw new java.lang.Exception(); 
    } 

DAO

public class StateDaoImpl extends GenericDaoImpl<State, Integer> implements StateDao { 
} 

个GenericDaoImpl

public class GenericDaoImpl<T,PK extends Serializable> implements GenericDao<T,PK> { 
    public SessionFactory sessionFactory; 
    public void setSessionFactory(SessionFactory sessionFactory) { 
    this.sessionFactory = sessionFactory; 
    } 

    public Session getSession() { 
    return sessionFactory.getCurrentSession(); 
    } 

    public PK create(T o) { 
    Session ss= getSession(); 
    ss.save(o); 
    return null; 
    } 

hibernate.cfg

<hibernate-configuration> 
    <session-factory> 
    <property name="connection.pool_size">1</property> 
    <property name="dialect">org.hibernate.dialect.MySQLInnoDBDialect</property> 
    <property name="cache.provider_class">org.hibernate.cache.NoCacheProvider</property> 
    <property name="show_sql">true</property> 
    <property name="hbm2ddl.auto">update</property> 
    <property name="defaultAutoCommit">false</property> 
    <mapping class="com.alw.imps.pojo.State"/> 
    <mapping class="com.alw.imps.pojo.City"/> 
    </session-factory> 
</hibernate-configuration> 

因此,正如我说我的问题是交易没有得到回滚当我从法addCustomer抛出类型异常的异常()

+0

到目前为止,一切都看起来不错,它应该回滚事务。是否有可能交易可能开始在调用堆栈上方。也许如果你在你配置交易的地方添加spring configuration,它会有所帮助。 – 2013-05-07 14:48:24

+0

我不相信你的'MyService'类是完全代理的。您看到的回滚来自数据库,而不是来自事务。 – 2013-05-07 14:50:09

+0

请发布您的配置和您的调用堆栈方法签名/注释,以便我们可以更好地评估情况。 – fpmoles 2013-05-07 15:15:23

回答

12

您的交易没有回滚,因为我有没什么抛出异常:该addState()方法调用捕捉异常:

public void addState() { 
    try { 
     State state=new State(); 
     state.setStateName("Delhi"); 
     stateDao.create(state); 
     addCity(); 
     addCustomer(); 
    } 
    catch(Exception e) { 
     e.printStackTrace(); 
    } 
} 

所以事务春天代理没有看到任何异常抛出,不会回滚事务。

它适用于从DAO抛出的异常,因为DAO本身是事务性的,所以它自己的事务代理检测到DAO抛出的异常并将事务标记为回滚。然后将异常传播到服务并由您的代码捕获,但此时事务已标记为回滚。

+0

谢谢jb,这是我的错......这是一个愚蠢的错误,不能被接受。 – 2013-05-08 07:45:08

4

您的事务没有回滚,因为您没有让Exception到达Spring框架,您正在捕获代码本身的异常。 所以不是

public void addState() 
{ 
     try 
     { 
     State state=new State(); 
     state.setStateName("Delhi"); 
     stateDao.create(state); 
     addCity(); 
     addCustomer(); 
     } 
     catch(Exception e) 
     { 

      e.printStackTrace(); 
     } 
} 

使用

public void addState() 
{ 
     State state=new State(); 
     state.setStateName("Delhi"); 
     stateDao.create(state); 
     addCity(); 
     addCustomer(); 
} 
1

该交易尚未被回滚,因为你自己捕捉异常,通过写catch块..

这可以完成正常情况下,但在春季交易中,如果你这样做了,春季交易管理员如何知道异常情况正在发生......这就是为什么它不会回滚。

0

您可以在Spring API doc中找到大多数问题的答案。 @Transactional有一个字段Class<? extends Throwable>[] rollbackFor()

默认情况下,交易将在RuntimeExceptionError回滚但不是在检查异常(业务异常)参见org.springframework.transaction.interceptor.DefaultTransactionAttribute.rollbackOn(Throwable)了详细的解释。

这意味着,对于以下情况,无论主叫方如何处理例外情况,只有第一个RunTimeException情况下会默认调用roleback。

// Only this case would roll back by default 
@Override 
@Transactional 
public void testRollbackRuntimeException() { 
    // jpa operation. 
    throw new RuntimeException("test exception"); 
} 

// never roll back, because its caught. 
@Override 
@Transactional 
public void testRollbackRuntimeExceptionCaught() { 
    try { 
     throw new RuntimeException("test exception"); 
    } catch(Exception e) {} 
} 

// @Transactional(rollbackFor = Exception.class) would also rollback. but by default no 
@Override 
@Transactional 
public void testRollBackWithExceptionCaught() throws Exception { 
    throw new Exception("test exception"); 
} 

// never roll back because the checked exception is caught. 
@Override 
@Transactional 
public void testRollBackWithExceptionCaught() { 
    try { 
     throw new Exception("test exception"); 
    } catch (Exception e) {} 
} 

而且大部分可能要回滚为undistinguishedly检查异常,使用 @Transactional(rollbackFor = Exception.class)

相关问题