您可以在OSGi环境(例如Karaf)中使用Hibernate 5.2 StatelessSession而不使用JTA吗?

时间:2018-08-13 15:28:17

标签: java hibernate osgi jta karaf

我正在尝试使用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功能“ transaction”使其正常运行。在karaf控制台中,我执行了feature:install transaction。这将安装OSGi事务管理器(由Apache Aries提供),该管理器注册javax.transaction.TransactionManager的Service实现,从而允许org.hibernate.osgi.OsgiJtaPlatform类定位它并摆脱上述Exception。 此代码似乎在那之后起作用:事务被毫无问题地提交,并且数据得以持久保存。

但是我仍然有一个问题:StatelessSession是否使用JTA Transactions?

在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。

1 个答案:

答案 0 :(得分:2)

我看事物的方式。为了获得非JTA事务,您需要使Hibernate确信它不在启用JTA的环境中。这意味着不要启用JDBC不要启用JMS不要启用tansactions

这是正在发生的事情>

  1. 休眠视图。从休眠的角度来看,“ org.hibernate.engine.transaction.spi.TransactionFactory”决定了它在哪种环境中使用,并取决于环境,它将初始化基于JDBC或基于JTA的事务管理器。您可以在第2.2章及其后的参考文献https://docs.jboss.org/hibernate/orm/4.0/devguide/en-US/html/ch02.html

  2. 中阅读
  3. Karaf根据文档要点4.16.4 https://karaf.apache.org/manual/latest/#_transaction_jta

  

Apache Karaf提供了容器管理的事务,可以通过   OSGi服务。

接下来的句子是

  

但是,已安装交易功能(作为传递功能   安装企业功能(如jdbc或jms)时的依赖性   功能)。

这基本上意味着,一旦启用JDBC服务,您将获得JTA事务处理管理器。

另一方面,由于您尝试使用StatelessHibernateSession,所以我的假设是您正在尝试实现性能。一个友好的建议:)

  1. 确保在阅读思想@BatchSize时一次获取多个集合
  2. 在生成ID时,请确保序列的分配大小合理
  3. 确保已将jdbc批处理大小配置为适当的值。
  4. 确保您与Fetch.Select有懒惰的关系

忘记了无状态会话:)您可能会惊讶于仅从休眠状态中可以获得多少性能。