Pouvez-vous utiliser une StatibSession Hibernate 5.2 dans un environnement OSGi (comme Karaf) sans utiliser JTA?

J’essaie d’utiliser une StatelessSession pour effectuer des insertions en bloc dans un environnement OSGi (Karaf 4.0.7), mais j’essaie de valider ma transaction

be.ikan.lib.orm.base.exceptions.PersistenceBrokerException: org.hibernate.TransactionException: Cannot resortingeve 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 resortingeve the TransactionManager OSGi service! at org.hibernate.osgi.OsgiJtaPlatform.resortingeveTransactionManager(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 resortingeve the TransactionManager OSGi service! at org.hibernate.osgi.OsgiJtaPlatform.resortingeveTransactionManager(OsgiJtaPlatform.java:46)[62:org.hibernate.osgi:5.2.17.Final] 

Je n’utilise pas JTA pour gérer mes transactions, j’ai défini hibernate.transaction.coordinator_class = jdbc. Le code qui utilise une session normale fonctionne correctement. Il existe une autre partie de l’application qui s’exécute dans un environnement non OSGi et où StatelessSession fonctionne correctement.

Je l’ai retrouvé dans la source Hibernate et trouvé dans 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(); } } 

Puisque la session n’est pas fermée et que StatelessSessionImpl.isFlushModeNever () renvoie toujours la valeur false, la méthode getJtaPlatform () est toujours appelée, ce qui échoue car elle peut trouver un JtaPlatform (org.hibernate.osgi.OsgiJtaPlatform), mais elle ne le fait pas. t configuré (parce que je ne l’utilise pas).

Cela signifie-t-il que vous ne pouvez pas utiliser une StatelessSession sans configurer JTA?

J’utilise Hibernate 5.2.17. Soit dit en passant, cette approche a bien fonctionné dans Hibernate 4.3.7, mais il n’existait alors aucun paquet hibernate-osgi et il semble que la classe StatelessSessionImpl ait subi des modifications importantes.


Après une enquête plus approfondie, j’ai réussi à le faire fonctionner en installant la fonctionnalité “transaction” de Karaf. Dans la console Karaf, j’ai exécuté la feature:install transaction . Cela installe un gestionnaire de transactions OSGi (fourni par Apache Aries), qui enregistre une implémentation de service pour javax.transaction.TransactionManager, ce qui permet à la classe org.hibernate.osgi.OsgiJtaPlatform de le localiser et de supprimer l’exception ci-dessus. Le code semble fonctionner après cela: les transactions sont validées et les données conservées.

Mais je rest toujours avec la question: StatelessSession utilise-t-il ou non les transactions JTA?

Dans la partie non OSGi de l’application, qui s’exécute dans Tomcat, j’ai trouvé des journaux de débogage.

 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 utilise donc org.hibernate.engine.transaction.jta.platform.internal.NoJtaPlatform.

Dans le journal karaf, j’ai trouvé les propriétés avec lesquelles la SessionFactory est instanciée:

 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: {, hibernate.transaction.jta.platform=org.hibernate.osgi.OsgiJtaPlatform@7d6ea302, } 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 

J’ai essayé de configurer la plate-forme jta sur NoJtaPlatform en ajoutant à hibernate.properties

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

Mais cela n’a eu aucun effet: il a néanmoins indiqué que la fabrique de sessions avait été créée avec OsgiJtaPlatform.

Si je peux en quelque sorte configurer Hibernate de sorte qu’il utilise la plate-forme NoJtaPlatform de Karaf, je pense que je n’aurais pas besoin de la fonctionnalité supplémentaire de “transaction”. Cela me convaincrait également que l’application utilise uniquement les transactions JDBC, et non JTA.

La façon dont je vois les choses. Pour obtenir des transactions non JTA, vous devez convaincre Hibernate que ce n’est pas dans un environnement compatible JTA. Ce qui signifie que n’activez pas JDBC n’activez pas JMS n’activez pas les transactions

Voici ce qui se passe>

  1. Vue Hibernate. Du sharepoint vue de l’hibernation, c’est «org.hibernate.engine.transaction.spi.TransactionFactory» qui détermine le type d’environnement dans lequel il est utilisé et, en fonction de l’environnement, il initialisera le gestionnaire de transactions basé sur JDBC ou basé sur JTA. Vous pourrez le lire au chapitre 2.2 et dans les références suivantes https://docs.jboss.org/hibernate/orm/4.0/devguide/en-US/html/ch02.html

  2. Karaf selon le sharepoint documentation 4.16.4 https://karaf.apache.org/manual/latest/#_transaction_jta

Apache Karaf fournit des transactions gérées par conteneur, disponibles sous forme de services OSGi.

Et la phrase suivante est que

Cependant, la fonctionnalité de transaction est installée (en tant que dépendance transitive) lors de l’installation de fonctionnalités d’entreprise (telles que les fonctionnalités jdbc ou jms, par exemple).

Cela signifie fondamentalement que vous obtiendrez un gestionnaire de transactions JTA une fois que vous aurez activé le service JDBC.

Sur une autre note puisque vous essayez d’utiliser StatelessHibernateSession, je suppose que vous essayez d’atteindre des performances. Un conseil sympathique 🙂

  1. Assurez-vous d’extraire plusieurs collections à la fois en lisant @BatchSize.
  2. Assurez-vous que vous avez une bonne taille d’allocation pour les séquences lorsque vous générez des ID
  3. Assurez-vous d’avoir configuré la taille de lot jdbc sur une valeur correcte.
  4. Assurez-vous d’avoir des relations paresseuses avec Fetch.Select

Et oubliez la session sans état 🙂 Vous serez peut-être surpris de la performance que vous pouvez tirer en veille prolongée seul.