@Transactional和级联之间的联系是什么?

时间:2011-09-15 19:34:54

标签: spring hibernate transactions

在Spring JUnit测试中存在@Transactional注释与在持久化/合并JPA2实体时级联之间似乎存在联系。

我暂时没有手头的配置,但也许这会给这里的某个人敲响一声?


在三个级别上假设一个简单的JPA实体案例:实体A引用类B的实体,而类B的实例引用类C的实例。

A - > B - > ç

A类将ALL级联为B.并且B将ALL级联为C.而C类具有使用@PrePersist和@PreUpdate注释的事件侦听器方法。它会记录一条消息,以证明级联到达那里。


现在,以某种方式修改实体C并要求实体管理器合并或持久化A的实例。逻辑上,实体C最终将被持久化或合并。由于级联已设置为ALL,从A到B到C。

当Spring单元测试未使用@Transactional注释时,来自C类事件侦听器方法的日志消息将打印其消息。行。

但是当 使用@Transactional注释时,根本不会打印任何消息。事实上,C类数据库没有提交任何内容。仅适用于A类。因此,我得出结论,级联并没有从A到C。

删除注释可以解决问题。


有人知道吗? :-)逻辑上我认为交易和级联是两个完全分开的事情。


典型的测试用例配置:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("/test-beans.xml")
@TransactionConfiguration
@Transactional
public class MyUnitTest {

...

  @Test
  public void testSomething() {}  

...

}

Spring xml配置文件的摘录 - 我认为没什么好看的......

  <context:annotation-config />

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

  <context:component-scan base-package="com.foo.bar"  />

  <bean id="jpaTemplate" class="org.springframework.orm.jpa.JpaTemplate">
    <property name="entityManagerFactory" ref="entityManagerFactory" />
  </bean>

  <bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
    <property name="persistenceXmlLocation" value="/META-INF/persistence.xml"/>
    <property name="persistenceUnitName" value="bar" />
  </bean>

  <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
    <property name="entityManagerFactory" ref="entityManagerFactory" />
  </bean>

从persistence.xml中提取

<persistence-unit name="bar" transaction-type="RESOURCE_LOCAL">
    <provider>org.hibernate.ejb.HibernatePersistence</provider>
    <properties>
      <property name="hibernate.connection.driver_class" value="com.mysql.jdbc.Driver" />
      <property name="hibernate.connection.url" value="jdbc:mysql://localhost:3306/bar" />
      <property name="hibernate.connection.username" value="bar" />
      <property name="hibernate.connection.password" value="pwd" />
      <property name="hibernate.cache.provider_class" value="org.hibernate.cache.NoCacheProvider"/>
      <property name="hibernate.hbm2ddl.auto" value="create"/>
      <property name="dialect" value="org.hibernate.dialect.MySQLDialect" />
    </properties>
  </persistence-unit>

  • Spring 3.0.6 ORM / CONTEXT / TEST
  • Hibernate 3.6.7.Final
  • JUnit 4.9
  • JPA2

1 个答案:

答案 0 :(得分:0)

发现它!启用事务时,不正确的实体管理器使用情况变坏。它与持久性无关,但在它之前完成。导致持久性以某种方式失败。

我实现了一个需要EntityManager的Query结果迭代器。我以为我可以从jpaTemplate的EntityManagerFactory创建它。

final EntityManager em = jpaTemplate.getEntityManagerFactory().createEntityManager();
return new QueryIterator<T>(em.createQuery("FROM Foo"));

显然不是。似乎必须以不同的方式获得EntityManager。如下文所述。

jpaTemplate.execute(new JpaCallback() {
  @Override
  public Object doInJpa(final EntityManager em) throws PersistenceException {
    return new QueryIterator<T>(em.createQuery("FROM Foo"));
  }
});

现在一切正常。正如它应该是,无论交易是否存在。 : - )