我正在尝试使用StatelessSession在OSGi环境中进行一些批量插入(Karaf 4.0.7),但是当我尝试提交我的事务时,我得到了
be.ikan.lib.orm.base.exceptions.PersistenceBrokerException: org.hibernate.TransactionException: Cannot retrieve the TransactionManager OSGi service!
at be.ikan.lib.orm.hibernate.broker.HibernateStatelessPersistenceBrokerImpl.commitTransaction(HibernateStatelessPersistenceBrokerImpl.java:118)[79:be.ikan.lib.orm:7.0.0]
at be.ikan.scm4all.business.server.bs.pack.PackageServiceImpl.createLevelRequestFileRevisionAssociations(PackageServiceImpl.java:1412)[72:be.ikan.scm4all.daemons.server:5.8.0]
at be.ikan.scm4all.phases.core.level.LinkFileRevisionsPhase.execute(LinkFileRevisionsPhase.java:99)[72:be.ikan.scm4all.daemons.server:5.8.0]
at Proxy5a8c2944_a0d5_4e21_a1b7_3f30296f5993.execute(Unknown Source)[:]
at be.ikan.scm4all.phases.impl.DefaultPhaseExecutionImpl.execute(DefaultPhaseExecutionImpl.java:152)[114:be.ikan.scm4all.daemons.shared:5.8.0]
at be.ikan.scm4all.daemons.server.monitor.MonitorThread.run(MonitorThread.java:231)[72:be.ikan.scm4all.daemons.server:5.8.0]
Caused by: org.hibernate.TransactionException: Cannot retrieve the TransactionManager OSGi service!
at org.hibernate.osgi.OsgiJtaPlatform.retrieveTransactionManager(OsgiJtaPlatform.java:51)[62:org.hibernate.osgi:5.2.17.Final]
at org.hibernate.osgi.OsgiJtaPlatform.getCurrentStatus(OsgiJtaPlatform.java:98)[62:org.hibernate.osgi:5.2.17.Final]
at org.hibernate.internal.StatelessSessionImpl.flushBeforeTransactionCompletion(StatelessSessionImpl.java:667)[60:org.hibernate.core:5.2.17.Final]
at org.hibernate.internal.StatelessSessionImpl.beforeTransactionCompletion(StatelessSessionImpl.java:644)[60:org.hibernate.core:5.2.17.Final]
at org.hibernate.engine.jdbc.internal.JdbcCoordinatorImpl.beforeTransactionCompletion(JdbcCoordinatorImpl.java:473)[60:org.hibernate.core:5.2.17.Final]
at org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorImpl.beforeCompletionCallback(JdbcResourceLocalTransactionCoordinatorImpl.java:156)[60:org.hibernate.core:5.2.17.Final]
at org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorImpl.access$100(JdbcResourceLocalTransactionCoordinatorImpl.java:38)[60:org.hibernate.core:5.2.17.Final]
at org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorImpl$TransactionDriverControlImpl.commit(JdbcResourceLocalTransactionCoordinatorImpl.java:231)[60:org.hibernate.core:5.2.17.Final]
at org.hibernate.engine.transaction.internal.TransactionImpl.commit(TransactionImpl.java:68)[60:org.hibernate.core:5.2.17.Final]
at be.ikan.lib.orm.hibernate.broker.HibernateStatelessPersistenceBrokerImpl.commitTransaction(HibernateStatelessPersistenceBrokerImpl.java:114)[79:be.ikan.lib.orm:7.0.0]
... 5 more
Caused by: org.hibernate.TransactionException: Cannot retrieve the TransactionManager OSGi service!
at org.hibernate.osgi.OsgiJtaPlatform.retrieveTransactionManager(OsgiJtaPlatform.java:46)[62:org.hibernate.osgi:5.2.17.Final]
我不使用JTA来管理我的事务,我设置了hibernate.transaction.coordinator_class = jdbc。使用常规Sesssion的代码运行正常。应用程序的另一部分在非OSGi环境中运行,并且StatelessSession可以正常工作。
我将它跟踪到Hibernate源代码并在org.hibernate.internal.StatelessSessionImpl中找到:
@Override
public void flushBeforeTransactionCompletion() {
boolean flush = false;
try {
flush = (
!isClosed()
&& !isFlushModeNever()
&& !JtaStatusHelper.isRollback(
getJtaPlatform().getCurrentStatus()
) );
}
catch (SystemException se) {
throw new HibernateException( "could not determine transaction status in beforeCompletion()", se );
}
if ( flush ) {
managedFlush();
}
}
由于会话未关闭,并且StatelessSessionImpl.isFlushModeNever()始终返回false,因此总是调用getJtaPlatform()方法,最终会失败,因为它可以找到JtaPlatform(org.hibernate.osgi.OsgiJtaPlatform),但它不是'配置(因为我不使用它)。
那么这是否意味着你不能在没有配置JTA的情况下使用StatelessSession?
我正在使用Hibernate 5.2.17。顺便说一句,这种方法在Hibernate 4.3.7中工作正常,但是没有hibernate-osgi包,看起来StatelessSessionImpl类经历了一些重大的变化。
经过一些进一步的调查,我设法通过安装Karaf功能“交易”来实现它。在karaf控制台,我执行了feature:install transaction
。这将安装一个OSGi事务管理器(由Apache Aries提供),它为javax.transaction.TransactionManager注册一个Service实现,它允许org.hibernate.osgi.OsgiJtaPlatform类找到它并摆脱上面的Exception。代码似乎在此之后起作用:事务提交没有问题,数据保持不变。
但我还是留下了一个问题:StatelessSession是否使用JTA事务?
在我在Tomcat中运行的应用程序的非OSGi部分中,我在调试日志中找到了它
2018-08-29 13:29:00,615 [localhost-startStop-1] DEBUG JtaPlatformInitiator - No JtaPlatform was specified, checking resolver
2018-08-29 13:29:00,617 [localhost-startStop-1] DEBUG JtaPlatformResolverInitiator - No JtaPlatformResolver was specified, using default [org.hibernate.engine.transaction.jta.platform.internal.StandardJtaPlatformResolver]
2018-08-29 13:29:00,629 [localhost-startStop-1] DEBUG StandardJtaPlatformResolver - Could not resolve JtaPlatform, using default [org.hibernate.engine.transaction.jta.platform.internal.NoJtaPlatform]
所以Hibernate使用org.hibernate.engine.transaction.jta.platform.internal.NoJtaPlatform。
在karaf日志中,我找到了实例化SessionFactory的属性:
2018-08-29 14:45:48,897 | DEBUG | e: pid=[server]) | SessionFactoryImpl | 72 - org.jboss.logging.jboss-logging - 3.3.1.Final | Building session factory
2018-08-29 14:45:48,936 | DEBUG | e: pid=[server]) | SessionFactoryImpl | 72 - org.jboss.logging.jboss-logging - 3.3.1.Final | Session factory constructed with filter configurations : {}
2018-08-29 14:45:48,937 | DEBUG | e: pid=[server]) | SessionFactoryImpl | 72 - org.jboss.logging.jboss-logging - 3.3.1.Final | Instantiating session factory with properties: {<a lot of properties>, hibernate.transaction.jta.platform=org.hibernate.osgi.OsgiJtaPlatform@7d6ea302, <more properties>}
2018-08-29 14:45:48,969 | DEBUG | e: pid=[server]) | SessionFactoryImpl | 72 - org.jboss.logging.jboss-logging - 3.3.1.Final | Instantiated session factory
我尝试通过添加到hibernate.properties将jta平台设置为NoJtaPlatform
hibernate.transaction.jta.platform=org.hibernate.engine.transaction.jta.platform.internal.NoJtaPlatform
但这没有任何效果:它仍然记录了会话工厂是使用OsgiJtaPlatform创建的。
如果我可以以某种方式配置Hibernate以便它使用Karaf中的NoJtaPlatform,那么我认为我不需要额外的“事务”功能。它还会让我相信应用程序只使用JDBC事务,而不是JTA。
我看待事物的方式。为了获得非JTA事务,您需要说服Hibernate它不在启用JTA的环境中。这意味着不启用JDBC不启用JMS不启用tansactions
这是正在发生的事情>
Apache Karaf提供容器管理的事务,可用作OSGi服务。
而下一句就是那个
但是,在安装企业功能(例如jdbc或jms功能)时,会安装事务功能(作为传递依赖项)。
这基本上意味着一旦启用JDBC服务,您将获得JTA事务管理器。
另一方面,由于您尝试使用StatelessHibernateSession,我的假设是您正在尝试实现性能。友好的建议:)
忘掉无状态会话:)你可能会惊讶于你可以从单独的hibernate中挤出多少性能。