2013-05-07 81 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)

相關問題