2012-02-14 129 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注释的方法中。