1

次のようなさまざまな理由により、既存のアプリケーションで sessionFactory Bean の作成を変更しました。

<bean id="sessionFactory"
       class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
       <property name="dataSource" ref="dataSource" />
       <property name="mappingLocations" ref="hibernateMappingFiles" />
       <property name="hibernateProperties" ref="hibernateProperties" />
   </bean>

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

   <bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
        <property name="sessionFactory" ref="sessionFactory" />
    </bean>

に:

<bean id="entityManagerFactory"
        class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
        <property name="dataSource" ref="dataSource" />
        <property name="persistenceUnitName" value="spring-jpa" />
    </bean>

    <bean id="sessionFactory" factory-bean="entityManagerFactory" factory-method="getSessionFactory" />

    <tx:annotation-driven transaction-manager="transactionManager" />
    <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
        <property name="entityManagerFactory" ref="entityManagerFactory" />
    </bean>

これは、新しく追加した永続ユニットです。

<persistence-unit name="spring-jpa">
        <provider>org.hibernate.ejb.HibernatePersistence</provider>
        <exclude-unlisted-classes>true</exclude-unlisted-classes>
        <properties>
            <property name="hibernate.dialect" value="org.hibernate.dialect.HSQLDialect" />
            <property name="hibernate.show_sql" value="false" />
            <property name="hibernate.format_sql" value="true" />
            <property name="hibernate.hbm2ddl.auto" value="none" />
            <property name="javax.persistence.validation.mode" value="none" />
            <property name="hibernate.jdbc.use_streams_for_binary"
                value="true" />
            <property name="hibernate.jdbc.fetch_size" value="100" />
            <property name="hibernate.current_session_context_class" value="org.springframework.orm.hibernate3.SpringSessionContext" />
            <property name="hibernate.ejb.cfgfile" value="/hibernate.cfg.xml" />
        </properties>
    </persistence-unit>

その後、多くのJunit 統合テストのトランザクション ブロックでInvalidComponentException を受け取りました。例えば:

createFolder ( "/examples/inheritance" );
transactionTemplate.execute ( new TransactionCallbackWithoutResult () {

            @Override
            protected void doInTransactionWithoutResult ( TransactionStatus status ) {
                for ( Resource r : Arrays.asList ( abstractComponent, concreteAComponent, concreteBComponent ) ) {
                    ComponentVersion c;
                    try {
                        c = componentService.validateAssignValues ( new ModelSource ( loadResource ( r ) ), null, TechnicalVersion.INITIAL_VERSION,
                                ModelVersion.INITIAL_VERSION, ModelVersionIncrement.MAJOR );
                    } catch ( InvalidComponentException e ) {
                        fail ( "Invalid Component: " + e.getMessage () );
                        return;
                    } catch ( IOException e ) {
                        fail ( "IOException: " + e.getMessage () );
                        return;
                    }
                    sessionFactory.getCurrentSession ().save ( c.getModelElement () );
                    sessionFactory.getCurrentSession ().save ( c );
                }
            }
        } );

例外は次の場所でスローされます。

catch ( InvalidComponentException e ) { fail ( "無効なコンポーネント: " + e.getMessage () );

java.lang.AssertionError: Invalid Component: The inherited component does not exist: name=/examples/inheritance/AbstractComponent
    at org.junit.Assert.fail(Assert.java:93)
    at info.server.component.FindComponentHierarchyTest$1.doInTransactionWithoutResult(FindComponentHierarchyTest.java:83)
    at org.springframework.transaction.support.TransactionCallbackWithoutResult.doInTransaction(TransactionCallbackWithoutResult.java:33)
    ...

問題は sessionFactory.getCurrentSession ().save ( c ); にありました。代わりに私は電話しなければなりませんでした:

Session session = sessionFactory.getCurrentSession ();
        session.save ( c );
        session.flush ();

これで、HibernateTransactionManager が JpaTransactionManager とは異なる動作をすることがわかりました。しかし、session.flush() を毎回手動で呼び出さなければならない場合、それは痛みとパフォーマンス キラーです。特に、オブジェクトを削除しようとすると、同じ問題が発生します。マージしてから削除するか、2 つのトランザクションに分割する必要があります。

session.flush() を追加せずにこの問題を解決するには、どのように JpaTransactionManager を構成する必要がありますか? 新しく追加した persistence.xml を試してみましたが、役に立ちませんでした。私は感謝し、それはどんな助けにもなります。


両方のバリアントで実際のフラッシュモードが何であるかを確認したところ、AUTO です。そして、私は電話をかけようとしましem.setFlushMode(FlushModeType.COMMIT)たが、フラッシュモードはまったく変更されず、常にAUTOであり、((Session)em.getDelegate()).setFlushMode(FlushMode.MANUAL)この例外が発生しています:

org.hibernate.SessionException: Session is closed!
    at org.hibernate.impl.AbstractSessionImpl.errorIfClosed(AbstractSessionImpl.java:72)
    at org.hibernate.impl.SessionImpl.setFlushMode(SessionImpl.java:1423)
    at info.novatec.np.server.component.FindComponentHierarchyTest.importComponents(FindComponentHierarchyTest.java:78)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    at java.lang.reflect.Method.invoke(Method.java:597)
    at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:44)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15)
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:41)
    at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:27)
    at org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:74)
    at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:83)
    at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:72)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:231)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:48)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:231)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:60)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:229)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:50)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:222)
    at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
    at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:71)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:292)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:174)
    at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50)
    at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)
4

1 に答える 1

1

例外メッセージとアサーション エラーのみを出力し、実際の例外スタックを表示しないため、不完全なスタック トレースが返されることに注意してください (e.printStackTrace() または catch で何かを実行します)。とにかく、これはビジネス上の非技術的/休止状態/JPA 例外のように見えるので、解決策はないと思います。

flush() で動作する場合、これはおそらく現在は flushmode=MANUAL になっていることを意味しますが、flushmode=AUTO であった可能性があります。

Hibernate で使用可能なオプションについては、ここで説明します: org.hibernate.FlushMode ところで、手動による flushmode は JPA 仕様の一部ではないようです: javax.persistence.FlushModeType

したがって、実際のフラッシュモードを確認してみてください。たとえば、次のようにします。

em.getFlushMode()

その結果も確認する必要があります。

((Session)em.getDelegage()).getFlushMode()

Hibernate 構成ファイル hibernate.cfg.xml をインポートしているためです。おそらく、適切なフラッシュモードまたはあなたのような特定のケースで何かを設定しない、休止状態にいくつかのバグがあります。

また、すべてのアプリケーションでフラッシュモードが一貫しているかどうかも確認してください (明示的に変更しない場合...)。Spring @Transactionnal 属性を「readonly=true」またはそのようなもので使用している場合、休止状態のフラッシュモードは自動的に手動に設定されます。これらのアノテーションを使用しない場合は、2003 年以降のトランザクション コールバック システムでトランザクションを処理する代わりに、おそらく良い考えです。


実際には JpaTemplate があるようです。

このコードを参照してください: http://massapi.com/source/apache-camel-2.5.0/components/camel-jpa/src/main/java/org/apache/camel/component/jpa/JpaTemplateTransactionStrategy.java.html

Javadoc によると、TransactionTemplate は JDBC のような低レベルのリソースを処理するために行われます。ニーズに合ったテンプレートを使用する必要があります。そうしないと、奇妙な副作用が発生する可能性があります。

于 2011-12-14T14:27:13.430 に答える