Я пытаюсь использовать 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.