【问题标题】:migrating from HibernateTransactionManager to JpaTransactionManager从 HibernateTransactionManager 迁移到 JpaTransactionManager
【发布时间】:2012-01-20 04:31:30
【问题描述】:

我更改了现有应用程序中的 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 中进行了尝试,但这并没有帮助。 我会很感激,如果有任何帮助都会很棒。


我刚刚检查了我的实际刷新模式是什么,两种变体都是自动的。 我试过打电话给em.setFlushMode(FlushModeType.COMMIT),但flushmode根本没有改变,它总是自动的,((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)

【问题讨论】:

  • 实际上,根据您的堆栈,您没有在 doInTransactionWithoutResult 方法中调用“setflushmode”,而是直接在您的测试中似乎尚未打开会话... Spring 自动为您打开会话/事务但这并不意味着您可以在代码中的任何位置访问会话

标签: hibernate spring jpa sessionfactory transactionmanager


【解决方案1】:

请注意,您给了我们一个不完整的堆栈跟踪,因为您只打印异常消息和断言错误,但没有向我们显示真正的异常堆栈(执行 e.printStackTrace() 或您的捕获中的某些内容)。 无论如何,这看起来像是一个业务,非技术/休眠/jpa 例外,所以我认为它不会带来任何解决方案。

如果它与flush()一起工作,这可能意味着你现在处于flushmode=MANUAL, 而您可能处于flushmode=AUTO。

Hibernate 的可用选项如下所述: org.hibernate.FlushMode 顺便说一句,手动刷新模式似乎不是 JPA 规范的一部分: javax.persistence.FlushModeType

因此,您可以尝试检查您的实际刷新模式。 例如这样做:

em.getFlushMode()

您还应该检查该结果:

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

因为您要导入 Hibernate 配置文件 hibernate.cfg.xml。 也许休眠中有一些错误没有设置适当的刷新模式或在某些特定情况下(如您的情况)。

还要检查你的flushmode是否在你的所有应用程序上都是一致的(当你没有显式修改它时......),因为如果你使用带有“readonly=true”或类似的东西的Spring @Transactionnal属性,休眠刷新模式自动设置为手动。 如果您不使用这些注释,那么从 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 等低级资源。您应该使用适合您需要的模板,否则您可能会产生奇怪的副作用。

【讨论】:

  • 感谢您的回复 Sebastien,我刚刚检查了我的实际冲洗模式是什么,两种变体都是自动的。而且我尝试调用 em.setFlushMode(FlushModeType.COMMIT) 但flushmode根本没有改变它总是自动的并且使用 ((Session)em.getDelegate()).setFlushMode(FlushMode.MANUAL) 我得到sessionException,作为回复发布。感谢您的帮助
猜你喜欢
  • 2012-09-02
  • 2016-01-15
  • 1970-01-01
  • 2012-12-04
  • 2011-04-26
  • 2015-07-23
  • 2020-05-31
  • 2010-10-26
  • 2022-01-14
相关资源
最近更新 更多