您可以在不使用 JTA 的情况下在 OSGi 环境(如 Karaf)中使用 Hibernate 5.2 StatelessSession 吗?

Posted

技术标签:

【中文标题】您可以在不使用 JTA 的情况下在 OSGi 环境(如 Karaf)中使用 Hibernate 5.2 StatelessSession 吗?【英文标题】:Can you use a Hibernate 5.2 StatelessSession in an OSGi environment (like Karaf) without the use of JTA? 【发布时间】:2019-01-20 09:18:21 【问题描述】:

我正在尝试使用 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。 使用常规会话的代码运行良好。应用程序的另一部分在非 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 注册一个服务实现,它允许 org.hibernate.osgi.OsgiJtaPlatform 类定位它并摆脱上述异常。 之后代码似乎可以工作:事务提交没有问题并且数据被持久化。

但我仍然有一个问题: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。

【问题讨论】:

【参考方案1】:

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

这是正在发生的事情>

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

    中阅读

    Karaf 根据文档点 4.16.4 https://karaf.apache.org/manual/latest/#_transaction_jta

Apache Karaf 提供容器管理事务,可用作 OSGi 服务。

接下来的句子就是那个

但是,事务功能已安装(作为传递 安装企业功能(如 jdbc 或 jms)时 例如功能)。

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

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

    确保在阅读想法时一次获取多个集合@BatchSize 确保在生成 Id 时为序列分配合适的大小 确保您已将 jdbc 批处理大小配置为合适的值。 确保您与 Fetch.Select 有惰性关系

忘记无状态会话 :) 您可能会惊讶于仅凭休眠就能挤出多少性能。

【讨论】:

以上是关于您可以在不使用 JTA 的情况下在 OSGi 环境(如 Karaf)中使用 Hibernate 5.2 StatelessSession 吗?的主要内容,如果未能解决你的问题,请参考以下文章

我可以在不使用 xml 文件的情况下在列表视图中添加视图吗

如何在不使用对话框的情况下在操作栏上方显示视图?

如何在不使用“|”的情况下在一行中连接两个集合

如何在不使用count(*)的情况下在greenplum中查找表中的行数

在不安装 Visual Studio 的情况下在机器上调试代码

是否可以在不重新启动服务器的情况下在远程 weblogic 上重新部署应用程序?