2011-09-15 10 views
2

Spring JUnitテストで@Transactionalアノテーションが存在し、JPA2エンティティを永続/マージするときにカスケードするリンクがあるようです。@トランザクションとカスケードのリンクは何ですか?

私は現時点での設定は行っていませんが、ここに誰かにベルが鳴るのでしょうか?


3つのレベルでJPAエンティティの単純なケースを想定:エンティティAは、クラスBのエンティティを参照すると、クラスBのインスタンスは、クラスC.

Aのインスタンス参照 - > B - > Cを

クラスAはBをALLにカスケードします.BはALLをCにカスケードします。クラスCには@PrePersistと@PreUpdateでアノテーションされたイベントリスナメソッドがあります。カスケード接続を証明するメッセージをログに記録します。


さて、いくつかの方法で、エンティティCを変更し、マージしたり、最終的に保持されますA.論理エンティティCのインスタンスを持続またはもマージするエンティティマネージャをお願いします。カスケーディングはクラスAからBからCにALLに設定されています。

Springユニットテストに@Transactionalアノテーションが付いていないと、クラスCのイベントリスナーメソッドからのログメッセージがメッセージを出力します。 OK。

しかし、が@Transactionalで注釈されたの場合、メッセージは一切表示されません。そして実際には、クラスCのデータベースには何もコミットされていません。クラスAの場合のみです。したがって、カスケード処理ではAからCへの変換はできませんでした。

注釈を削除すると問題が解決します。


誰か手掛かりがありますか? :-)論理的には、トランザクションとカスケードは完全に別々の2つの問題だと私は考えます。


典型的なテストケースの設定:

@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> 

図書館

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

カスケードとトランザクションは完全に分離した問題ではありません。カスケードとは、ある種のSQLをデータベースに送信することを意味します。これは、トランザクションをコミットするときに発生します。 entityManager.getTransaction.begin()と.commit()を使用して単体テストでトランザクションをプログラム的に開始したり終了したりしてください。この非標準的なすべてのジャンボを使用しないでください。 JPA2には、トランザクションがアプリケーションサーバー/ ejbコンテナの内部と外部でどのように動作するかについての非常に明確なドキュメントがあります。 –

+0

私の知る限りでは、カスケードは持続性プロバイダ(つまり、休止状態)によって強制されます。取引の実行方法にかかわらず。だから私の質問はまだ立っている:トランザクションが存在するときにプロバイダがカスケードしないのはなぜですか? –

+0

あなたは試してみることが2つあります:1. trueをあなたの休止状態の設定とデバッグに追加してSQLログを有効にして、両方の状況(そしていつ) 。その後、Spring @ Transactionと手動でトランザクションを停止し、トランザクションを停止して同じことが起きているかどうかを確認します。 –

答えて

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")); 
    } 
}); 

これですべて正常に動作します。トランザクションが存在するかどうかにかかわらず、そうであるようになっています。 :-)

関連する問題