Можете ли вы использовать Hibernate 5.2 StatelessSession в среде OSGi (например, Karaf) без использования JTA?

Я пытаюсь использовать 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), но это не " t (потому что я его не использую).

Значит ли это, что вы не можете использовать StatelessSession без настройки JTA?

Я использую Hibernate 5.2.17. Этот подход, кстати, отлично работал в Hibernate 4.3.7, но тогда не было пучка спящего-оси, и, похоже, класс StatelessSessionImpl претерпел некоторые существенные изменения.


После некоторого дальнейшего расследования мне удалось заставить его работать, установив функцию транзакции Karaf. В консоли karaf я выполнил feature:install transaction. Это устанавливает OSGi Transaction Manager (предоставленный Apache Aries), который регистрирует реализацию службы для javax.transaction.TransactionManager, которая позволяет классу org.hibernate.osgi.OsgiJtaPlatform найти его и избавиться от вышеуказанного Исключения. После этого код работает после этого: транзакции совершаются без проблем, и данные сохраняются.

Но у меня все еще остается вопрос: использует ли StatelessSession транзакции JTA или нет?

В части, отличной от OSGi приложения, которая работает в Tomcat, я нашел в журналах отладки

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>, hibern[email protected]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

Я попытался установить платформу jta на NoJtaPlatform, добавив в hibernate.properties

hibernate.transaction.jta.platform=org.hibernate.engine.transaction.jta.platform.internal.NoJtaPlatform

Но это не повлияло: он все еще регистрировал, что фабрика сеансов была создана с использованием OsgiJtaPlatform.

Если я смогу как-то настроить Hibernate так, чтобы он использовал NoJtaPlatform в Karaf, тогда я думаю, что мне не нужна дополнительная функция транзакции. Это также убедит меня, что приложение использует только транзакции JDBC, а не JTA.

Ответы

Ответ 1

То, как я вижу вещи. Чтобы получить транзакции Non JTA, вам нужно убедить Hibernate, что он не включен в среду с поддержкой JTA. Что означает, что не включить JDBC, не включить JMS, не активировать tansactions

Вот что происходит>

  1. Вид спящего режима. С точки спящего режима это "org.hibernate.engine.transaction.spi.TransactionFactory", который решает, в какой среде он используется внутри, и в зависимости от среды он будет инициализировать JDBC-based или JTA-менеджер транзакций. Этот юй можно прочитать в главе 2.2 и последующих ссылках https://docs.jboss.org/hibernate/orm/4.0/devguide/en-US/html/ch02.html

  2. Karaf в соответствии с пунктом 4.16.4 документации https://karaf.apache.org/manual/latest/#_transaction_jta

Apache Karaf предоставляет транзакции, управляемые контейнерами, доступные в качестве служб OSGi.

И следующее предложение таково:

Тем не менее, функция транзакции устанавливается (как транзитивная зависимость) при установке корпоративных функций (например, jdbc или jms).

Это, в основном, означает, что вы запустите JTA transactio manager после активации службы JDBC.

На другой ноте, поскольку вы пытаетесь использовать StatelessHibernateSession, моя презумпция заключается в том, что вы пытаетесь достичь производительности. Дружелюбный совет :)

  1. Убедитесь, что вы сразу получаете несколько коллекций при чтении мысли @BatchSize
  2. Убедитесь, что у вас есть хороший размер распределения для последовательностей при генерации идентификаторов
  3. Убедитесь, что вы настроили размер партии jdbc на хорошее значение.
  4. Удостоверьтесь, что у вас есть ленивые отношения с Fetch.Select

И забудьте о сессии без гражданства :) Вы можете быть удивлены, сколько вы можете выжать из спящего режима в одиночку.