从 HibernateTransactionManager 迁移到 JpaTransactionManager
由于各种原因,我将现有应用程序中的 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 个事务。
我如何配置 JpaTransactionManager 来解决这个问题而不添加 session.flush() ? 我在新添加的 persistence.xml 中尝试过,但这没有帮助。 我将不胜感激,如果有任何帮助,我将非常感激。
我刚刚检查了两种变体的实际冲洗模式是什么,它是自动。 我尝试调用 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)
I changed the sessionFactory bean creation in an existing application because of various reasons from :
<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>
to:
<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>
this is my newly added persistence-unit:
<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>
After that I received in the transaction block in many Junit integration tests an InvalidComponentException. For example:
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 );
}
}
} );
the exception is thrown at:
catch ( InvalidComponentException e ) {
fail ( "Invalid Component: " + 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)
...
the Problem was at sessionFactory.getCurrentSession ().save ( c ); instead i had to call:
Session session = sessionFactory.getCurrentSession ();
session.save ( c );
session.flush ();
Now I know that the HibernateTransactionManager works diffrent then the JpaTransactionManager. But if i have to call the session.flush() manually everytime, that is a pain and preformance killer.
notably I´m getting the same problem when I try to remove an objekt. I have to merge then remove or split into 2 transactions.
How do I have to configurate the JpaTransactionManager to solve this problem without adding session.flush()?
I tried in my newly added persistence.xml, but that didn´t help.
I would be thankful and It would be great for any help.
I´ve just checked what my actual flushmode is, with both variants, and it is AUTO.
And I've tried to call em.setFlushMode(FlushModeType.COMMIT)
but the flushmode is not changed at all it is allways AUTO and with ((Session)em.getDelegate()).setFlushMode(FlushMode.MANUAL)
I'm getting this exception:
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)
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
请注意,您给我们的堆栈跟踪不完整,因为您只打印异常消息和断言错误,但没有向我们显示真正的异常堆栈(执行 e.printStackTrace() 或您的 catch 中的其他操作)。
无论如何,这看起来像是一个商业、非技术/hibernate/jpa 异常,所以我认为它不会带来任何解决方案。
如果它与flush()一起工作,这可能意味着你现在处于flushmode=MANUAL,
当你可能处于flushmode=AUTO 时。
Hibernate 的可用选项如下所述:
org.hibernate.FlushMode
顺便说一句,手动刷新模式似乎不是 JPA 规范的一部分:
javax.persistence.FlushModeType
因此,您可以尝试检查实际的刷新模式是什么。
例如,通过执行以下操作:
您还应该检查结果:
因为您正在导入 Hibernate 配置文件 hibernate.cfg.xml。
也许休眠中存在一些错误,没有设置适当的刷新模式,或者在某些特定情况下(例如您的情况)。
还要检查您的刷新模式在所有应用程序上是否一致(当您没有显式修改它时...),因为如果您使用带有“readonly=true”或类似内容的 Spring @Transactionnal 属性,则休眠刷新模式是自动设置为手动。
如果你不使用这些注释,那么最好不要在 2003 年的事务回调系统中处理事务。
实际上似乎有一个 JpaTemplate。
看这段代码:
根据 Javadoc,TransactionTemplate 是为了处理 JDBC 等低级资源而完成的。您应该使用适合您需要的模板,否则可能会产生奇怪的副作用。
Notice that you give us an incomplete stacktrace since you only print the exception message, and the assertion error, but do not show us the real exception stack (do e.printStackTrace() or something in your catch).
Anyway this looks like to be a business, non technical/hibernate/jpa exception so i don't think it will bring any solution.
If it works with flush() this probably means that you are now in flushmode=MANUAL,
while you were probably in flushmode=AUTO.
The available options for Hibernate are described here:
org.hibernate.FlushMode
Btw it seems the manual flushmode is not part of the JPA specification:
javax.persistence.FlushModeType
So you may try to check what is you actual flushmode.
For exemple by doing:
You should also check that result:
Because you are importing an Hibernate config file hibernate.cfg.xml.
Perhaps there are some bugs in hibernate that do not set an appropriate flushmode or something in some specific cases like yours.
Check also if your flushmode is consistent on all your application (when you don't explicitly modify it...), because if you are using Spring @Transactionnal attributes with "readonly=true" or some things like that, the hibernate flushmode is automagically set to manual.
And if you don't use these annotations it's perhaps a good idea instead of handling transactions in transaction callback system from 2003.
Actually it seems that there is a JpaTemplate.
See this code:
http://massapi.com/source/apache-camel-2.5.0/components/camel-jpa/src/main/java/org/apache/camel/component/jpa/JpaTemplateTransactionStrategy.java.html
According to the Javadoc, TransactionTemplate is done for dealing with low-level resources like JDBC. You should use the template that fits to your needs or you may have strange side effects.