2011-05-06 68 views
2

我正在開發一個獨立的spring/jpa/hibernate應用程序。回滾對我獨立的Spring應用程序不起作用

我遇到的問題是即使引發了RuntimeException,我的應用程序也不會回滾事務。

這裏是我的配置:

<context:annotation-config /> 
    <context:component-scan base-package="com.jeanbaptistemartin"/> 
    <context:property-placeholder location="classpath:application.properties"/> 
    <bean id="gestionnaireMailing" class="com.jeanbaptistemartin.desktop.JFrameGestionnaireMailing" init-method="init" > 

    </bean> 

    <bean id="cacheManager" class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean"> 
     <property name="configLocation" value="classpath:ehcache.xml"/> 
     <property name="shared" value="true"/> 
    </bean> 

    <bean id="mailSender" class="org.springframework.mail.javamail.JavaMailSenderImpl"> 
     <property name="host" value="${mail.server}"/> 
     <property name="port" value="${mail.port}"/> 
     <property name="javaMailProperties"> 
      <props> 
       <prop key="mail.smtp.connectiontimeout">2000</prop>  
       <prop key="mail.smtp.timeout">2000</prop>  
      </props>  
     </property> 
    </bean> 
    <bean id="velocityEngine" class="org.springframework.ui.velocity.VelocityEngineFactoryBean"> 
     <property name="velocityProperties"> 
      <value> 
      resource.loader=class 
      class.resource.loader.class=org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader 
      </value> 
     </property> 
    </bean> 
    <bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"> 
     <property name="persistenceUnitName" value="jbmPU" /> 
     <property name="persistenceXmlLocation" value="classpath:/META-INF/persistence.xml" /> 
     <property name="dataSource" ref="dataSource" /> 
     <property name="jpaVendorAdapter"> 
      <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter"> 
       <property name="showSql" value="${database.showSql}" /> 
       <property name="generateDdl" value="${database.generateDdl}"/> 
       <property name="databasePlatform" value="${database.dialect}"/> 
      </bean> 
     </property> 
    </bean> 
    <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"> 
     <property name="driverClass" value="${database.driver}"/> 
     <property name="jdbcUrl" value="${database.url}"/> 
     <property name="user" value="${database.username}"/> 
     <property name="password" value="${database.password}"/> 
     <property name="minPoolSize" value="5" /> 
     <property name="maxPoolSize" value="20" /> 
     <property name="idleConnectionTestPeriod" value="3000" /> 
     <property name="loginTimeout" value="300" /> 
    </bean> 
    <bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor" /> 
    <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager"> 
     <property name="entityManagerFactory" ref="entityManagerFactory" /> 
     <property name="dataSource" ref="dataSource"/> 
    </bean> 
    <tx:annotation-driven transaction-manager="transactionManager" /> 

我的交易方法:

@Transactional(propagation = Propagation.REQUIRED, rollbackFor = {RuntimeException.class}) 
    public boolean mailAbonne(List<Sculpture> sculpturesChoisiesPourMailing, Abonne abonne) { 
     try { 
      for (Sculpture sculpture : sculpturesChoisiesPourMailing) { 
       MailingAbonnePK mapk = new MailingAbonnePK(sculpture.getSculptureID(), abonne.getAbonneID()); 
       MailingAbonne ma = new MailingAbonne(mapk, new Date()); 
       dao.persistMailingAbonnee(ma); 
      } 
      envoyerMail(sculpturesChoisiesPourMailing, abonne);//this method sometimes throws a RuntimeException. 
      return true; 
     } catch (RuntimeException e) { 
      log.error("Exception"); 
      log.error(e); 
      throw new RuntimeException(); 
     } 
    } 

在吾道:

@PersistenceContext(type = PersistenceContextType.TRANSACTION) 
    private EntityManager entityManager; 

現在關於我的應用程序的當前行爲一句話:

when一個RuntimeException或其子類由envoyerMail引發,這些應用程序只能無限期掛起。

現在另一個關於我的應用程序的行爲的字。

我mailAbonne方法被稱爲一個循環,如下所示:

for (Abonne abonne : totalAbonnes) { 
    mailAbonne(sculpturesChoisiesPourMailing, abonne); 
} 

理想我想爲一個迭代循環的失敗,或者如果一個RuntimeException在迭代3升出的成功原子即總共5次迭代,然後我會在我的數據庫中獲得與4次成功迭代相對應的數據,並且對應於失敗迭代的數據將被回滾。

任何人都可以請幫忙嗎?

J.

回答

5

首先,你並不需要指定rollbackFor = {RuntimeException.class}。默認行爲是回滾任何運行時異常。

你的問題似乎是你從同一個bean的另一個方法調用你的事務方法。 Spring會自動啓動和停止事務,因爲它將每個bean都包裝在處理此事務工作的代理中。當您從同一個bean調用方法時,代理不能攔截該調用併爲您啓動/停止事務。因此,您應該將事務性方法放入另一個bean中。

然後爲您的迭代。爲了工作,你需要

  • 使含有環不是事務性的方法,這樣就mailAbonne每次調用啓動新事務
  • 或使mailAbonne方法REQUIRES_NEW的傳播,爲了使它擁有自己獨立的交易

當然,你還需要包裝mailAbonne的每個呼叫在try/catch塊內部循環,使運行時異常被捕獲並mailAbonne下一個電話,甚至可以做到如果當前的失敗。

+0

非常感謝JB Nizet!春天我沒有意識到這一點。你的建議對問題進行分類。再次感謝Julien。 – JBAM 2011-05-06 12:44:28