2012-02-14 152 views
0

我是Spring的新手,我無法在「必需」模式下進行交易傳播。春季交易「必需」傳播

下面是一個例子:

@Controller 
public class ExampleController 
{ 
    @Autowired 
    Foo foo; 

    @Autowired 
    Bar bar; 

    @RequestMapping(value = "/example") 
    public String submitForm(Model model) throws Exception 
    { 
     User user = new User("Joe", "Bloggs"); 
     user = foo.save(user); 
     bar.simpleMethod(user); 
     return "success"; 
    } 
} 

@Repository 
public class Foo 
{ 
    // A JPA repository 
    private EntityManager em; 

    @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED) 
    public User save(User user) 
    { 
     return this.em.merge(user); 
    } 

    @PersistenceContext 
    void setEntityManager(EntityManager entityManager) 
    { 
     this.em = entityManager; 
    } 
} 

public class Bar 
{ 
    @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED) 
    public void simpleMethod(User user) 
    { 
     // Do something... 
    } 
} 

applicationContext.xml文件(重要位):

<beans xmlns="http://www.springframework.org/schema/beans" 
     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
     xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx" 
     xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.1.xsd"> 
    <context:property-placeholder location="/WEB-INF/jdbc.properties" /> 

    <bean id="dataSource" class="org.springframework.jdbc.datasource.TransactionAwareDataSourceProxy"> 
     <constructor-arg> 
      <bean class="org.springframework.jdbc.datasource.DriverManagerDataSource"> 
       <property name="driverClassName" value="${db.driverClassName}" /> 
       <property name="url" value="${db.url}" /> 
       <property name="username" value="${db.username}" /> 
       <property name="password" value="${db.password}" /> 
      </bean> 
     </constructor-arg> 
    </bean> 

    <bean id="jpaAdapter" class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter"> 
     <property name="databasePlatform" value="org.hibernate.dialect.MySQL5Dialect" /> 
     <property name="showSql" value="${db.showSql}" /> 
     <property name="generateDdl" value="${db.generateDdl}" /> 
    </bean> 

    <!-- enabling annotation driven configuration /--> 
    <context:annotation-config /> 
    <context:component-scan base-package="my.package" /> 

    <!-- Instructs the container to look for beans with @Transactional and decorate them --> 
    <tx:annotation-driven transaction-manager="transactionManager" proxy-target-class="true" /> 

    <!-- FactoryBean that creates the EntityManagerFactory --> 
    <bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"> 
     <property name="jpaVendorAdapter" ref="jpaAdapter" /> 
     <property name="jpaProperties"> 
      <props> 
       <prop key="hibernate.show_sql">true</prop> 
       <prop key="hibernate.format_sql">true</prop> 
       <prop key="hibernate.hbm2ddl.auto">update</prop> 
      </props> 
     </property> 
     <property name="dataSource" ref="dataSource" /> 
    </bean> 

    <!-- A transaction manager for working with JPA EntityManagerFactories --> 
    <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager"> 
     <property name="entityManagerFactory" ref="entityManagerFactory" /> 
    </bean> 
</beans> 

如果excep在bar.simpleMethod()foo.save(...)不會回滾(或者可能是,但數據庫肯定不是)。有誰知道爲什麼?

回答

3

如果異常occours在bar.simpleMethod()foo.save(...)不回滾

而且,無論它應該是 - 你已經包裹你的交易單獨註解周圍Bar.simpleMethodFoo.save,所以這些會被執行兩個單獨的交易。如果Bar.simpleMethod失敗,它會回滾自己的交易,但Foo.save的交易已被提交。沒有任何一項交易涉及兩者。

您需要將這兩個操作封裝在一個方法中,該方法在單個事務中執行這兩個操作。這最好通過引入一個由控制器調用的額外組件來完成。此方法將使用@Transactional進行註釋,並執行Bar.simpleMethodFoo.saveBar.simpleMethodFoo.save上的@Transactional註釋將成爲同一整體交易的一部分。

+0

謝謝 - 完美的答案! – satoshi 2012-02-14 11:56:48

2

這裏有兩個獨立的交易。第一個是承諾,第二個是異常回滾。這裏真的沒有什麼奇怪的。爲了讓這兩個電話參與同一個事務,您應該將它們放在一個用@Transactional註釋的方法中。