2011-09-15 29 views
2

在持久化/合併JPA2實體時,似乎在Spring JUnit測試中存在@Transactional註釋與級聯之間存在關聯。@Transactional和級聯之間的聯繫是什麼?

我目前沒有配置,但是這可能對此處的某個人響個不停?


假設JPA實體的簡單情況在三個層次:實體A引用類B的實體和B類的該實例引用類C.

A的一個實例 - >乙 - 「ç

A級將ALL級聯到B級,而B級將ALL級聯到C級.C類具有用@PrePersist和@PreUpdate註釋的事件偵聽器方法。它記錄了一條消息,以證明級聯使它到達那裏。現在


,修改實體下,在某種程度上,並要求實體管理器合併或持續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配置文件的提取物 - 沒有什麼花哨那裏,我想......從persistence.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-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> 

個圖書館

  • 春3.0.6 ORM/CONTEXT/TEST
  • 休眠3.6.7.Final
  • 的JUnit 4.9
  • JPA2
+1

級聯和交易不是完全分離的問題。級聯意味着將一些SQL發送到數據庫,並且當您提交事務時會發生這種情況(等等)。只需使用entityManager.getTransaction.begin()和.commit()在單元測試中以編程方式啓動和結束事務,不要使用所有這些非標準的spring mumbo jumbo。 JPA2有一個非常明確的文檔,說明事務如何在應用程序服務器/ ejb容器內部和外部工作。 –

+0

據我所知,級聯是由持久性提供者(即休眠)強制執行的。不管交易如何進行。所以我的問題仍然存在:爲什麼當交易存在時供應商不會進行級聯? –

+0

看,有兩件事你可以嘗試:1.通過添加到您的休眠配置和調試,以查看什麼SQL發送到數據庫在這兩種情況下(和什麼時候) 。然後拋棄Spring @Transactional並手動停止事務以查看是否發生了相同的事情。 –

回答

0

找到了!在啓用交易時,不正當的實體經理使用情況變差。這與持久性沒有關係,而是在它之前完成。以某種方式導致持久性失敗。

我實現了需要EntityManager的查詢結果迭代器。我想我可以從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")); 
    } 
}); 

現在一切正常。正如它應該是,無論交易是否存在。 :-)

相關問題