FLASH INFORMATIQUE FI



Persistance des objets Java avec Hibernate




Laurent BOATTO


Les développeurs le savent bien, la problématique de l’ORM (Object-Relational Mapping) consistant à mapper des objets métiers vers des bases de données relationnelles pose souvent de nombreuses difficultés. Le code nécessaire pour gérer le mapping est généralement répétitif, sujet aux bugs et difficile à maintenir. Des solutions existent depuis longtemps pour remédier à ce problème. On peut citer par exemple Cocobase [1], JDO [2], ou encore EJB CMP [3]. Ces solutions sont cependant souvent onéreuses, propriétaires, complexes à mettre en oeuvre, ou peu performantes. Le framework Java Hibernate change désormais la donne puisqu’il est gratuit, open source (license LGPL), rapide et simple à utiliser. Le but de cet article est d’en présenter les différentes possibilités, sans pour autant offrir un tutorial complet. Vous trouverez en effet toutes les informations complémentaires dont vous avez besoin sur le site www.hibernate.org.

La preuve par l’exemple

Prenons comme exemple une petite application désirant gérer une liste d’étudiant(e)s, ainsi que les cours auxquels ils/elles sont inscrit(e)s et les salles de ces cours. Le modèle de données (simplifié) pourrait être le suivant :

JPEG - 7.5 ko
modèle de données

Première étape : créer les classes de notre modèle de données

Le modèle de données étant défini, on crée tout d’abord une classe Java respectant les directives JavaBeans (un getter / setter pour chaque attribut, un constructeur public sans argument, etc.) pour chaque objet métier. La classe Student sera donc la suivante :
public class Student
{
 private int id;
 private String firstName;
 private String lastName;
 private int semester;
 private Collection courses;
 
 public int getId()
 {
   return id;
 }

 public void setId(int id)
 {
   this.id = id;
 }

 [...] // faire de même pour chaque attribut
}

Comme on peut le constater il n’y a ni interface spécifique à implémenter ni classe à étendre. Hibernate fonctionne avec n’importe quel type d’objet et ne nécessite aucune compilation supplémentaire, comme c’est le cas avec d’autres solutions.

Deuxième étape : décrire les objets dans un fichier HBM

Il est ensuite nécessaire de décrire dans un fichier HBM (pour hibernate-mapping) quels sont, pour chaque objet, les attributs qui doivent persister. Voici le mapping de notre objet Student :

1. <hibernate-mapping>
2. <class name="ch.epfl.kis.example.model.Student" table="student">
3.  <id name="id" column="id">
4.   <generator class="native"/>
5.  </id>
6.  <property name="firstName"/>
7.  <property name="lastName"/>
8.  <property name="semester"/>
9.  <set name="courses" table="student_course" lazy="true">
10.   <key column="studentId"/>
11.   <many-to-many class="ch.epfl.kis.example.model.Course" column="courseId"/>
12.  </set>
13. </class>
14. </hibernate-mapping>

Les lignes 3 à 5 définissent l’attribut utilisé pour l’identifiant de l’objet, ici id. Il est possible de préciser le générateur d’identifiant (ligne 4), native signifiant ici que l’on délègue cette tâche à la base de données (avec MySQL p.ex., la colonne aura automatiquement l’option AUTO_INCREMENT).

Le tag <property> permet quant à lui de définir un attribut simple. Tous les types primitifs de Java sont supportés (int, float, boolean, char, etc.) ainsi que certaines classes (String, Date). Il n’est pas toujours nécessaire d’indiquer le type de l’attribut. A la ligne 6 par exemple, seul le nom (firstName) est indiqué. Hibernate utilisera la réflexion Java pour déterminer qu’il s’agit d’un String, créant ainsi automatiquement une colonne de type CHAR dans la base.
Le tag <property> permet également de définir de nombreuses propriétés pour les attributs. On citera parmi tant d’autres la taille de la colonne (pour les types CHAR), les indexes à créer, les contraintes UNIQUE et NOT-NULL, etc.
Les lignes 9 à 12 définissent enfin la relation many-to-many qu’il y a entre la classe Student et la classe Course (un étudiant peut participer à plusieurs cours, un cours comporte plusieurs étudiants). Le paramètre lazy permet de ne charger les objets Course que lorsque l’application en fait explicitement la demande, plutôt qu’à la création de l’objet Student, ce qui peut améliorer sensiblement les performances.
Il est également possible d’indiquer dans un fichier HBM que l’on désire utiliser un cache pour certaines classes, permettant ainsi de diminuer considérablement le nombre de requêtes à la base.

Gestion des objets

Une fois notre mapping décrit, on peut commencer à interagir avec nos objets. Les fonctionnalités courantes CRUD (create, read, update, delete) sont très faciles à mettre en oeuvre. Commençons par créer et sauvegarder un objet Student :

1. // Création
2. Student student = new Student();
3. student.setFirstName("Aline");
4. student.setLastName("Delors");
5. student.setSemester(5);
6.
7. // Sauvegarde
8. Session session = HibernateManager.getSession();
9. Transaction transaction = session.beginTransaction();
10. session.save(student);
11. transaction.commit();

La ligne 8 crée un objet session permettant d’interagir avec la base de données. Les lignes 9 et 11 délimitent respectivement le début et la fin de la transaction. En cas de problèmes la méthode rollback de l’objet transaction permettra d’annuler les requêtes déjà effectuées.
Le listing précédent illustre bien la force d’Hibernate. Aucun code SQL n’est nécessaire, le développeur travaille uniquement avec des objets très simples. De plus, si le modèle de données vient à évoluer par la suite, il suffira de modifier le fichier HBM sans avoir à changer le code de sauvegarde correspondant.
Modifions maintenant notre objet Student en lui ajoutant un cours :

1. Collection courses = new HashSet();
2. // On admettra que l'objet mathCourse à été créé précédemment
3. courses.add(mathCourse);
4. student.setCourses(courses);
5. session.update(student);

Supprimons pour finir notre objet :

1. Transaction transaction = session.beginTransaction();
2. session.delete(student);
3. transaction.commit();

Recherches

Rechercher des objets avec Hibernate est tout aussi simple. Comme nous avons précédemment défini dans notre fichier HBM qu’il y avait une relation many-to-many entre Student et Course, récupérer tous les cours auxquels un(e) étudiant(e) participe ne nécessite qu’une seule ligne de code :

student.getCourses();

De la même manière, obtenir la liste des étudiant(e)s d’un cours donné est très simple :

mathCourse.getStudents();

Pour les requêtes plus complexes Hibernate offre un langage similaire à SQL, mais totalement orienté objet, nommé HQL.

Conclusion

Dans cet article nous avons vu quelques unes des possibilités offertes par Hibernate. Le fait d’utiliser ce framework permet d’augmenter fortement la productivité d’un développeur.
La plupart des étapes décrites précédemment peuvent en outre être automatisées. Des outils comme Together ou Rational permettent de générer visuellement les classes Java de notre modèle de données. Des tâches AN [4] fournies par Hibernate peuvent ensuite créer les fichiers HBM (mapping) correspondants.
Les performances restent quant à elles excellentes. L’overhead induit par Hibernate est de 10% environ, ce qui peut être largement compensé par l’utilisation de caches. Je ne saurai donc que trop vous conseiller d’abandonner définitivement JDBC [5] au profit d’Hibernate !

[1] Cocobase, solution commerciale d’ORM : www.thoughtinc.com/

[2] JDO, Java Data Object : java.sun.com/products/jdo

[3] EJB, Enterprise JavaBeans, architecture de composants : java.sun.com/products/ejb

[4] [ANT, outil de build Java : ant.apache.org

[5] JDBC, API Java permettant d’interagir avec une base de données : java.sun.com/products/jdbc



Cherchez ...

- dans tous les Flash informatique
(entre 1986 et 2001: seulement sur les titres et auteurs)
- par mot-clé

Avertissement

Cette page est un article d'une publication de l'EPFL.
Le contenu et certains liens ne sont peut-être plus d'actualité.

Responsabilité

Les articles n'engagent que leurs auteurs, sauf ceux qui concernent de façon évidente des prestations officielles (sous la responsabilité du DIT ou d'autres entités). Toute reproduction, même partielle, n'est autorisée qu'avec l'accord de la rédaction et des auteurs.


Archives sur clé USB

Le Flash informatique ne paraîtra plus. Le dernier numéro est daté de décembre 2013.

Taguage des articles

Depuis 2010, pour aider le lecteur, les articles sont taggués:
  •   tout public
    que vous soyiez utilisateur occasionnel du PC familial, ou bien simplement propriétaire d'un iPhone, lisez l'article marqué tout public, vous y apprendrez plein de choses qui vous permettront de mieux appréhender ces technologies qui envahissent votre quotidien
  •   public averti
    l'article parle de concepts techniques, mais à la portée de toute personne intéressée par les dessous des nouvelles technologies
  •   expert
    le sujet abordé n'intéresse que peu de lecteurs, mais ceux-là seront ravis d'approfondir un thème, d'en savoir plus sur un nouveau langage.