Migrer vers Hibernate 4

Récemment, nous avons décidé de migrer vers Hibernate 4 depuis la version 3.5.1 (vers la version 4.1.7 plus exactement). Au-delà de la volonté de se maintenir à jour, nous souhaitions profiter du module Hibernate de XStream permettant de sérialiser correctement les beans Hibernate.

Premier constat : il fut relativement difficile de trouver de la documentation sur le sujet, que ce soit des retours d’expérience, des tutoriels, des posts de forums… Et en particulier en ce qui concerne l’intégration avec Spring, la documentation officielle se contentant d’un laconique « See Javadoc »… Certes, il existe l’article « Migrer vers Spring 3.1 & Hibernate 4.1 » mais, là encore, l’aide est relativement mince.

C’est pourquoi nous avons décidé de partager notre expérience. Pour info, nous utilisons actuellement la version 3.1.3 de Spring.

Comment migrer vers Hibernate 4 ?

Une fois la mise à jour faite, voici la liste quasi exhaustive des modifications que nous avons dû apporter à nos projets :

  • org.hibernate.classic.Session n’existe plus, vous devrez utiliser org.hibernate.Session à la place. Il nous restait des traces historiques (archéologiques ?) de cette interface, voilà une occasion de nettoyer la poussière.
  • Nous utilisions jusque là des org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean afin de mapper les beans via des annotations plutôt qu’en XML. Maintenant, les LocalSessionFactoryBean & AnnotationSessionFactoryBean ne font plus qu’un : org.springframework.orm.hibernate4.LocalSessionFactoryBean supporte les deux modes de configuration.
  • Un certain nombres de propriétés de notre AnnotationSessionFactoryBeanse sont avérées obsolètes, à savoir :
    • schemaUpdate ;
    • configurationClass (plus besoin de préciser org.hibernate.cfg.AnnotationConfiguration).
  • De même, certaines propriétés Hibernate de la Session Factory disparaissent (nous n’utilisions de toute façon pas de cache de second niveau…) :
    • hibernate.cache.use_second_level_cache ;
    • hibernate.cache.use_query_cache ;
    • hibernate.cache.provider_class.
  • Le transaction manager de Spring pour Hibernate 4 (HibernateTransactionManager) est désormais dans le package org.springframework.orm.hibernate4.
  • L’interface org.hibernate.usertype.UserType, permettant de customiser le comportement d’un type lors de l’écriture ou de la lecture en base, a quelque peu évolué mais rien de méchant : seules les signatures de nullSafeGet et de nullSafeSet ont bougés et proposent à présent un paramètre supplémentaire (SessionImplementor).

Et ce fut à peu près tout pour notre part ! Sachez que si vous utilisez JTA, ce qui n’est pas notre cas, il semblerait que la configuration de la Session Factory nécessite des informations supplémentaires. Je vous conseille de regarder du côté des propriétés Hibernate hibernate.transaction.jta.platform et hibernate.transaction.factory_class.

Jusqu’ici, tout va bien…

Ce fut à peu près tout, enfin, pour ce qui est de la configuration. Car en relançant les tests unitaires, nous nous sommes confrontés à un autre problème : quelques uns desdits tests nous ont gratifiés du ô combien fameux « No Session found for current thread ». Cela concernait les cas où un service en appelle un autre et que les deux ne sont pas gérés par la même Session Factory.
Voici un exemple on ne peut plus simple :

  • Le service A est appelé ;
  • Un advice (AOP) ordonne au Transaction Manager correspondant (TransactionManagerA) de créer une transaction autour du service A et de lier la session Hibernate au ThreadLocal ;
  • Le service A s’exécute, jusqu’à arriver à l’appel d’ un second service nommé B ;
  • Toujours via un advice, le TransactionManagerB crée une nouvelle transaction et lie une nouvelle session Hibernate au ThreadLocal ;
  • Le service B s’exécute ;
  • Le service A finit de s’exécuter.

Ça, c’est le processus tel que nous l’imaginions. En réalité, la configuration de notre advice était erronée si bien qu’aucun Transaction Manager n’intervenait autour du service B. Pourtant, cela fonctionnait sous Hibernate 3. Comment est-ce possible ? Détaillons ce qui se passait dans le service B sous Hibernate 3 :

  • Le service exécute à un moment donné SessionFactory.getCurrentSession() ;
  • org.springframework.orm.hibernate3.SpringSessionContext.currentSession() est appelé ;
  • SessionFactoryUtils.doGetSession()est appelé :
    • On cherche si la Session Factory courante est liée au ThreadLocal (ceci se fait auprès du TransactionSynchronisationManager) ;
    • Vu qu’aucun Transaction Manager n’est intervenu, cette Session Factory est introuvable ;
    • Cependant, SessionFactoryUtils.doGetSession() se montre conciliant et crée directement une session Hibernate grâce à la Session Factory.

Le support d’Hibernate 4 par Spring fonctionne quelque peu différemment. L’appel à org.springframework.orm.hibernate4.SpringSessionContext.currentSession() (la seconde étape ci-dessus) cherche la session (auprès du TransactionSynchronizationManager) et, si elle n’est pas trouvée, lève directement l’exception « No Session found for current thread »… Pour corriger, il a suffi de configurer convenablement l’advice : le TransactionManager intercepte l’appel au service B, crée une transaction et lie la session Hibernate au ThreadLocal, bref, tout se passe bien.

Cela aura au moins eu le mérite de mettre en évidence le problème de configuration de l’AOP mais pas que : peut-être avez-vous noté l’absence de synchronisation entre les transactions, ce qui est autrement plus dérangeant.
Ce à quoi nous avons remédié. Et, plutôt qu’utiliser JTA, nous avons mis en place une solution bien plus légère qui fera l’objet d’un prochain article…

3 réflexions sur “ Migrer vers Hibernate 4 ”

  1. youness sur

    Bonjour

    très intéressant est c’est rare de trouver un sujet qui parle sur la migration

    merci  pour votre temps. est encore merci pour le partage de votre expérience

     

    ma question est ce que la volonté de se maintenir à jour, suffit pour faire une migration hibernate 4

    est une question vient à l’esprit. c’est quoi le plus qu’on va gagner lorsque on va migrer de hibernate 3 vers hibernate 4

    Est ce que la gestion de session est évoluer  ?

    Est ce que la performance de récupération est améliorer  ?

    Est ce que …. ????

    Merci Encore e votre temps,

    J’attend votre réponse.

     

     

     

    • olivier sur

      Mais de rien !
      Comme dit au tout début de l’article, la mise à jour était à nos yeux importante par rapport à XStream. Nous utilisons cette librairie pour sérialiser & désérialiser du XML et nous avions besoin de pouvoir le faire sur des objets comportant des propriétés en FetchType Lazy. Ceci nécessite l’utilisation d’un plugin XStream, uniquement compatible avec Hibernate 4.
      Nous faisons par ailleurs une utilisation assez classique d’Hibernate : essentiellement via Spring, sans cache de second niveau, listeners ou quoi que ce soit.
      Très sincèrement, nous n’avons pas constaté d’amélioration majeure après la mise à jour… Mais étant donné que la version 3 commence à sérieusement dater, je dirais que c’est plutôt une bonne idée si vous comptez maintenir votre projet à long terme. Cela finira probablement par être bloquant par rapport à d’autres libraires : par exemple, je ne suis pas convaincu de la compatibilité de Spring 4 avec Hibernate 3…

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *