Vous êtes sur la page 1sur 63

Architecture n tiers(Java EE) Partie 1: Mapping Objet Relationnel Chapitre 4: Hibernate

Gnralits
Outil ORM ou Cadre (Framework) de persistance libre (open source) grant la persistance des objets Java/JavaEE en base de donnes relationnelle [Wikipdia,Pat05] Version 3.2.x : implmentation du standard de persistance EJB 3.0 Java Persistence API (JPA) Possibilit dtre utilis aussi bien dans un dveloppement client lourd, que dans un environnement web lger de type Apache Tomcat ou dans un environnement J2EE complet [Wikipdia] Code SQL gnr lexcution via des informations fournies dans un document de correspondance (mapping) XML ou des annotations

Diffrents modules
Hibernate Core : API native implmentant les services de base pour la persistance
Mta-donnes au format XML Langage HQL et interface pour crire des requtes

Hibernate Annotations : Remplacement des fichiers XML par des annotations JDK 5.0 implmentant les annotations du standard JPA + annotations spcifiques Hibernate
3

Objectifs dHibernate
Que permet de faire Hibernate ? Hibernate soccupe du transfert des classes Java dans les tables de la base de donnes (et des types de donnes Java dans les types de donnes SQL) Quel avantage est apport par Hibernate ? Il rduit de manire significative le temps de dveloppement qui aurait t autrement perdu dans une manipulation manuelle des donnes via SQL et JDBC.
4

Architecture du noyau Hibernate


Fichier de configuration Version XML : hibernate.cfg.xml permettant un paramtrage plus fin Configuration par programmation

Architecture du noyau Hibernate

Architecture du noyau Hibernate


SessionFactory (org.hibernate.SessionFactory) :
Cache immuable (threadsafe) des correspondances (mappings) vers une (et une seule) base de donnes Coteuse construire car implique lanalyse des fichiers de Configuration Construite partir dun objet Configuration

Session (org.hibernate.Session) :
Objet mono-thread, dure de vie courte, reprsentant une conversation entre l'application et l'entrept de persistance Encapsule une connexion JDBC Contient un cache des objets persistants
7

Architecture du noyau Hibernate

Hibernate.cfg.xml
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd"> <hibernate-configuration> <session-factory> <property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver </property> <property name="hibernate.connection.password">root</property> <property name="hibernate.connection.url">jdbc:mysql://localhost:3306/orm </property> <property name="hibernate.connection.username">root</property> <property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect </property>
9

Hibernate.cfg.xml(suite)
<property name="hbm2ddl.auto">update</property> <property name="hibernate.show_sql">true</property> <property name="hibernate.transaction.factory_class">org.hibernat e.transaction.JDBCTransactionFactory</property> <property name="current_session_context_class">thread</property > <mapping resource="contexte/Employer.hbm.xml" /> </session-factory> </hibernate-configuration>
10

Configuration dHibernate
Dclaration du type de document utilis par lanalyseur syntaxique (parseur) XML pour valider le document de configuration daprs la DTD de configuration dHibernate :
<?xml version='1.0' encoding='utf-8'?> <!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD 3.0//EN " "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">

Paramtres de configuration ncessaires pour la connexion JDBC :


<property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver </property> <property name="hibernate.connection.password">root</property> <property name="hibernate.connection.url">jdbc:mysql://localhost:3306/orm </property> <property name="hibernate.connection.username">root</property> <property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect </property>

11

Configuration dhibernate
Activation de la gnration automatique des schmas de base de donnes - directement dans la base de donnes : <property name="hbm2ddl.auto">create</property>
Autre valeur update

Fichier de configuration (fichier de mapping) des classes persistantes : <mapping resource="contexte/Employer.hbm.xml"/>


12

Configuration par programmation


Configuration cfg = new Configuration() .addClass(Person.class) .addClass(Event.class) .setProperty(Environment.HBM2DDL_AUTO, "create"); cfg.setProperty("hibernate.show_sql", "true"); cfg.setProperty("hibernate.connection.driver_class", "com.mysql.jdbc.Driver ") .setProperty("hibernate.dialect", "org.hibernate.dialect.MySQLDialect") .setProperty("hibernate.connection.url", "jdbc:mysql://localhost:3306/orm") .setProperty("hibernate.connection.username", "root") .setProperty("hibernate.connection.password", "root") .setProperty("hibernate.order_updates", "true"); factory = cfg.buildSessionFactory(); 13

Environnement Hibernate
Bibliothques Hibernate Core (en plus de hibernate3.jar) : antlr.jar ANTLR (Another Tool for Language Recognition) - Indispensable lexcution commons-collections.jar Bibliothques du projet Apache Jakarta Commons pour manipuler les collections - Indispensable lexcution Jta.jar API JTA strandard requis pour les applications sexcutant en dehors dun serveur dapplication dom4j.jar Analyseur Syntaxique de configuration XML et de mapping - Indispensable lexcution log4j jar log4j.Mcanisme de log sous-jacent pouvant tre utilis par Commons Logging - Optionnel
14

Environnement Hibernate
Fichiers ncessaires avec Hibernate Core :
hibernate.cfg.xml : fichier de configuration globale contenant Les paramtres de connexion la base de donnes (pilote, login, mot de passe, url, etc.) Le dialecte SQL de la base de donnes La gestion de pool de connexions Le niveau de dtails des traces etc.

Pour chaque classe persistante :


ClassePersistante.java : Implmentation POJO (Plain Old Java Objects) de la classe ClassePersistante.hbm.xml : Fichier XML de correspondance (mapping) ClassePersistanteHome.java : Implmentation du DAO (Data Access Object) pour lisolation avec la couche de persistance Optionnel

15

Classes persistantes
Objets persistants implments sous la forme de POJO Pas dimplmentation de certaines interfaces dhritage de classes particulires Des rgles respecter : Implmenter un constructeur sans paramtre (pouvant tre priv mais de prfrence accessible par le paquetage) Fournir une proprit d'identifiant (optionnel mais fortement recommand) Implmenter des modificateurs (mutateurs - setter) et accesseurs(getter) pour chaque champ persistant
16

La classe Employer
package contexte; public class Employer implements java.io.Serializable{ private int id; private String nom; private String prenom; private float salaire; public Employer() {} public Employer(String nom, String prenom, Float salaire) { this.nom = nom; this.prenom = prenom; this.salaire = salaire; }
17

La classe Employer
public int getNo() { return no;} public void setNo(int no) { this.no = no;} public String getNom() { return nom;} public void setNom(String nom) { this.nom = nom;} public String getPrenom() { return prenom;} public void setPrenom(String prenom) { this.prenom = prenom;} public Float getSalaire() { return salaire;} public void setSalaire(Float salaire) { this.salaire = salaire;} }

18

Fichier de correspondance
Hibernate a besoin de savoir comment charger et stocker des objets dune classe persistante. Le fichier de mapping indique Hibernate quelle table dans la base de donnes il doit accder, et quelles colonnes de cette table il devra utiliser. Le fichier de mapping doit tre stock dans le mme rpertoire que le fichier source.
19

Employer.hbm.xml
<?xml version="1.0"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"> <hibernate-mapping package="contexte"> <class name="Employer" table="employee"> <id name="no" type="int"> <column name="no" /> <generator class="increment" /> </id> <property name="nom" type="java.lang.String"> <column name="nom" /> </property>
20

Employer.hbm.xml
<property name="prenom" type="java.lang.String"> <column name="prenom" /> </property> <property name="salaire" type="float"> <column name="salaire" /> </property> </class> </hibernate-mapping>
21

Pour manipuler les objets persistantes


Ouverture dune Session Hibernate [ Dbuter une transaction] . dbute une transaction ] fortement conseill Appliquer les oprations de Session pour interagir avec lenvironnement de persistance [Valider ( commit() ) la transaction en cours] Synchroniser avec la base de donnes (flush) et fermer la session
22

Manipuler les objets persistantes


SessionFactory sf= new Configuration().configure().buildSessionFactory(); sf.openSession(); Transaction tx = null; Session session=sf.getCurrentSession(); try {tx = session.beginTransaction(); Employer c1 = new Employer("Romdhani", "Mohamed",100f); session.save(c1); session.flush(); tx.commit(); } catch (Exception e) { if (tx != null) { tx.rollback(); sf.close();}}
23

Diagramme dtats des objets dune classe persistante

* Mthodes JPA - implmentes dans Hibernate EntityManager mais pas dans Hibernate Core
24

Contexte de persistance
Session associe un contexte de persistance : Vrification des modifications et synchronisation avec la base de donnes (automatic dirty checking) Garantie de lidentit Java Extension du contexte de persistance une conversation (unit de travail longue)
25

Contexte de persistance
Utilisation du cache : Pour vrifier les mises jour Pour amliorer les performances en diminuant linteraction avec la base de donnes Pour viter les conflits de reprsentation (pas deux objets correspondants au mme nuplet) Possibilit de grer le cache (dtachement dobjets et nettoyage du contexte de persistance)
26

Contexte de persistance
Oprations Session
Rcuprer une instance persistante Rendre une instance persistante Rendre persistantes les modifications apportes une instance persistante Rendre persistantes les modifications apportes une instance dtache R-attacher une instance dtache Dtacher une instance persistante Supprimer une instance persistante Rafrachir une instance Dtecter automatiquement un tat
27

Contexte de persistance
Rcuprer une instance persistante dans Hibernate Core : session.load(Class cl, serializable id) Leve dune exception irrcuprable s'il n'y a pas de ligne correspondante dans la base de donnes session .get(Class cl, serializable id) null si pas de nuplet correspondant dans la base
28

Contexte de persistance
Pour ces deux mthodes : Gnration dun ordre SQL un SELECT sur la base pour rcuprer lentit partir de son identificateur Possibilit de charger dans une instance nouvellement cre ou dans une instance existante Possibilit de transformer le SELECT en SELECT ... FOR UPDATE en utilisant LockMode.UPGRADE en 3me paramtre Possibilit de rcuprer une instance aussi par les API Query, Criteria, SQLQuery

29

Contexte de persistance
session.save(objet)
Pour rendre persistante une instance temporaire Gnration dune commande INSERT uniquement excute au moment du lancement de la mthode session.commit()

session.persist(objet) session.merge(objet)
Fusionne une instance dtache avec une instante persistante (existante ou charge depuis la base) Effectue un SELECT avant pour dterminer sil faut faire INSERT ou UPDATE
30

Contexte de persistance
Rendre persistante les modifications apportes une instance persistante : Pas de mthode particulire (automatic dirty checking) Tout modification dune instance persistante transactionnelle (objet charg, sauvegard, cr ou requt par la Session) est rendu persistant par la mthode flush() Surveillance (dirty checking) de toutes les instances persistantes par la session Instance persistante modifie = instance sale (dirty) Synchronisation avec la base dfinitive une fois la transaction sous-jacente valide
31

Contexte de persistance
Rendre persistante les modifications apportes une instance dtache : Pas de surveillance possible des instances dtaches ncessit de r-attacher les instances en rendant persistant les modifications apportes session.merge(objet)
Effectue un SELECT avant lUPDATE pour rcuprer les donnes dans la base et les fusionner avec les modifications apportes Retourne linstance persistante correspondante

session.update(objet)
Force la mise jour (UPDATE) de lobjet dans la base Lve une exception si une instance de mme identificateur existe dans la Session

32

Contexte de persistance
Dtacher une instance persistante : Plus de surveillance de linstance par la Session : Plus aucune modification rendue persistante de manire transparente Trois moyens de dtacher une instance : En fermant la session : session.close() En vidant la session : session.clear() En dtachant une instance particulire: session.evict(objet)
33

Contexte de persistance
Rendre un objet transient : Extraction dfinitive de lentit correspondante dans la base de donnes session.delete(objet) :
Enregistrement correspondant plus prsent dans la base

Instance toujours prsente dans la JVM tant que lobjet est rfrenc instance transiente
34

Correspondance des associations


Partie la plus complexe dont dpend les performances de lapplication Balises de correspondance des collections : <set>, <list>; <map>, <bag>, <array> Tags de correspondance des cardinalits/multiplicits : <one-to-one>, <many-to-one>, <many-to-many> Si correspondance dune collection : utilisation dune balise de collection contenant un tag de cardinalit Si correspondance dune association uni ou bidirectionnelle vers une entit : utilisation des balises de cardinalit
35

Correspondance des associations


<many-to-one> et <one-to-one> : associations uni ou bi-directionnelle vers une entit name : nom de la proprit column : nom de la cl trangre possibilit de balise <column> class : nom de la classe associe optionnel par dfaut le type de la proprit dtermin par rflexion cascade : Propagation des oprations de l'objet pre vers les objets associs optionnel + dautres cf. doc Hibernate
36

Many-to-one
Exemple dassociation uni-directionnelle :
public class Enseignant { private int id ; private String nom; private float salaire;

private Departement departement;


* 1

Enseignant

Departement
37

Many-to-one
<class name="Enseignant" table="enseignant"> <id name="id" type="int"> <column name="id"/> <generator class="native"/> </id> <property name="nom" type="string"><column name="nom"/> </property> <property name="salaire" type="float"><column name="salaire"/> </property> <many-to-one name="departement" class="persistence.Departement" > <column name="numero" not-null="true" /> </many-to-one> </class>
38

Many-to-one
Pour chaque opration basique de session:
persist(), merge(), saveOrUpdate(), delete(), lock(), refresh(), evict(), replicate() .

On lui correspond un style de cascade nomm:


create, merge, save-update, delete, lock, refresh, evict, replicate.

<one-to-one name="person cascade="persist"/> combinaison de cascade <many-to-one name="person" cascade="persist,delete,lock"/> Appliqu touts les types de casacade <many-to-one name="person" cascade=all"/>
39

One-to-one
La mthode la plus simple est dutiliser est de traiter une association one-to-one comme une association many-to-one on ajoutant la contrainte unique true

Enseignant

Adresse
40

One-to-one
package persistence; public class Adresse { private int numero; private String Rue; private String Ville; //Getters et setters } <hibernate-mapping package="persistence"> <class name="Adresse" table="adresse"> <id name="numero" type="int"> <column name="numero"/> </id> <property name="rue" type="string"><column name="rue"/> </property> <property name="ville" type="string"><column name="ville"/> </property> </class></hibernate-mapping>
41

One-to-One
Classe Enseignant public class Enseignant{ ... private Adresse adresse; } Enseignant.hbm.xml <class name="Enseignant" table="enseignant"> <many-to-one name="adresse" class="persistence.Adresse" cascade="all" unique="true"> <column name="num" not-null="true" /> </many-to-one>

42

One-to-One
On a mapp une association one-to-one unidirectionnelle dEnseignant vers Adresse Si on voulez transformer cette association en bidirectionnelle on devra ajouter un attribut enseignant dans la classe adresse
1 1

Enseignant

Adresse
43

One-to-One
Classe Adresse public class Adresse { private int numero; private String Rue; private String Ville; private Enseignant ens; //Getters et Setters Adresse.hbm.xml <one-to-one name="ens" class="Enseignant" property-ref="adresse" />

44

One-to-One
Une deuxime mthode de mapper une association One-to-one est de faire partager les deux objets(un Enseignant et une Adresse) la mme cl primaire. Ici si on va choisir que lenseignant est lobjet fort(master) et sa cl est gnr automatiquement donc un objet adresse doit partager la cl de lenseignant comme cl trangre. Chaque objet Adresse aura la mme valeur de la cl de lenseignant.
45

One-to-One
Adresse.hbm.xml
<id name="numero" column="ID"> <generator class="foreign"> <param name="property">ens</param> </generator> </id> . <one-to-one name="ens" class="Enseignant" cascade="all" constrained="true"/>

Enseignant.hbm.xml
<one-to-one name="adresse" class="persistence.Adresse" cascade="save-update,delete" />
46

Correspondance des associations


Implmentations des collections Set, List et Map propres Hibernate Balise propre chaque type dinterface : <set>, <list>, <map> etc. name : nom de la proprit contenant la collection table : nom de la relation contenant la collection optionnel par dfaut nom de la proprit - non utilis pour les associations one-to-many lazy : pour dsactiver l'initialisation tardive - par dfaut = true inverse : Pour dfinir la collection comme extrmit inverse de l'association bidirectionnelle.
47

One-to-Many
private Set<Enseignant> enseignants; <set name="enseignants" inverse="true" cascade="all" > <key column="id" /> <one-to-many class="Enseignant"/> </set>

48

Many-to-Many
On va ajouter notre projet la classe Module. Un enseignant peut enseigner plusieurs module et un module peut tre enseigner par plusieurs enseignant Enseignant private Set<Module> ens_mod;
<set name="ens_mod" table="ens_module" cascade="all" > <key column="id_ens" /> <many-to-many class="Module" column="id_mod" /> </set>
49

Many-to-Many
Module public class Module { private int codeModule; private String nom_module; private float coef; private Set<Enseignant> ens_mod; . } <set name="ens_mod" table="ens_module" cascade="all" > <key column="id_mod" /> <many-to-many class="Enseignant" column="id_ens"/> </set>
50

Many-to-Many
Ne pas oublier de grer les deux extrmits des associations En relationnel, contrairement au Java, ralisation dune seule opration : mise jour ou initialisation de la cl trangre En Java : deux oprations une chaque extrmit de lassociation Ne pas oublier de spcifier inverse= "true" lune des extrmit dans le fichier de correspondance pour viter la cration de deux ordres SQL Penser regrouper les mthodes dinstanciation au sein dune mthode mtier de cohrence

51

Hritage
Hibernate supporte les trois stratgies d'hritage de base :
Une table par hirarchie de classe (table per class hierarchy) Une table par classe fille (table per subclass) Une table par classe concrte (table per concrete class)

Hibernate supporte en plus une quatrime stratgie, lgrement diffrente, qui supporte le polymorphisme :
le polymorphisme implicite (Il ne sera pas tudi en cours)

52

Hritage
Une table par hirarchie de classe (table per class hierarchy) 1 table
<class name="Article" table="ARTICLE_PERCLASSHIERARCHY"> <id name="idArticle" type="long" column=ARTICLE_ID"> <generator class="native" /> </id> <discriminator column="ARTICLE_TYPE" type="string" /> <property name="prixArticle" column="prixArticle" /> <subclass name="Stylo" discriminator-value="STYLO"> <property name="couleur" column="COULEUR" /> </subclass> <subclass name="Ram" discriminator-value="RAM"> <property name="capacite" type="int" column="CAPACITE" /> </subclass> </class>
53

Hritage
Une table par hirarchie de classe (table per class hierarchy)
<class name="Article" table="ARTICLE_PERCLASSHIERARCHY"> <id name="idArticle" type="long" column="PAYMENT_ID"> <generator class="native" /> </id> <discriminator column="ARTICLE_TYPE" type="string" /> <property name="prixArticle" column="prixArticle" /> <subclass name="Stylo" discriminator-value="STYLO"> <property name="couleur" column="COULEUR" /> </subclass> <subclass name="Ram" discriminator-value="RAM"> <property name="capacite" type="int" column="CAPACITE" /> </subclass> </class>

54

Hritage
Une table par classe fille (table per subclass ) 3 tables
<class name="Article" table="ARTICLE_PERCONCRETECLASS"> <id name="id" type="long" column=ARTICLE_ID"> <generator class="native" /> </id> <property name="prixArticle" column="prixArticle" /> <joined-subclass name="Stylo" table="STYLO_PERCONCRETE"> <key column="ARTICLE_id" /> <property name="couleur" column="COULEUR" /> </joined-subclass> <joined-subclass name="Ram" table="RAM_PERCONCRETE"> <key column="ARTICLE_id" /> <property name="capacite" type="int" column="CAPACITE" /> </joined-subclass> </class>

55

Hritage
Une table par classe concrte (table per concrete class) 2 tables
<class name="Ram" table="RAM_ARTICLE"> <id name="idArticle" type="long" column="ARTICLE_ID"> <generator class="native" /> </id> <property name="capacite" type="int" column="CAPACITE" /> <property name="prixArticle" column="prixArticle" /> </class> <class name="Stylo" table="STYLO_ARTICLE"> <id name="idArticle" type="long" column="ARTICLE_ID"> <generator class="native" /> </id> <property name="prixArticle" column="prixArticle" /> <property name="couleur" column="COULEUR" /> </class>

56

Hritage
Inconvnient majeur de cette solution est quun stylo et un ramette peuvent avoir la mme valeur de cl primaire. Pour rsoudre ce problme il faudra utiliser ce code qui ne marche pas sous MYSQL <class name=Article" > <id name="id" type="long" column="ID_Article"> <generator class="sequence"/> </id> <property name=prixArticle" column=prixArticle" /> <union-subclass name=Stylo" table=Stylo_Article"> <property name=couleur" type="string" column=couleur" /> </union-subclass> <union-subclass name=Ram" table=Ram_Article"> <property name=capacite" column=capacite" /> </union-subclass> </class>
57

Hritage
La solution avec le SGBD Mysql est:

<class name="Article" abstract="true"> <id name="idArticle" type="long" column="ID_Article"> <generator class="increment" /> </id> <property name="prixArticle" column="prixArticle" /> <union-subclass name="Stylo" table="Stylo_Article"> <property name="couleur" type="string" column="couleur " /> </union-subclass> <union-subclass name="Ram" table="Ram_Article"> <property name="capacite" column="capacite" /> </union-subclass> </class>

58

Requte HQL
"Langage de requtes orientes objet" ou encapsulation du SQL selon une logique oriente objet Requtes HQL (et SQL natives) reprsentes avec une instance de org.hibernate.Query Obtention dune Query en utilisant la Session courante : session.createQuery (string) Clauses : from, select, where Invocation de la mthode list() retour du rsultat sous forme de liste Query req = session.createQuery("from Module"); List modules=req.list();
59

Requte HQL
Interface Query fournit deux mthodes pour rcuprer un sous ensemble du rsultat. Trs utile pour la pagination. Query req = session.createQuery("from Module"); req.setFirstResult(20);// premier enregistrement(commence par 0) req.setMaxResults(10);// nombre denregistrement List modules=req.list(); Avec HQL on peut ajouter des paramtres la requte Query req = session.createQuery("from Module where id=?"); Req.setInt(0,100); List modules=req.list();

60

Requte HQL
Autre mthode Query req = session.createQuery("from Module where id=:id_m"); Req.setInt(id_m,100); List modules=req.list(); from : Clause suivie dun nom de classe et non de la relation de BD : from Module Utilisation des alias Query req = session.createQuery("from Module as m where m.id=:id_m");
61

Requte HQL
join : Pour excuter des jointures (inner join) Select e from Enseignant e join e.department Departement where Department.nom = Etude Where: Equivalent celle de SQL, on peut utiliser and, or et not from Enseignant e where e.nom like %M% and e.salaires between 100 and 200; Utilisation de null from Enseignant e where e.department is not null
62

Requte SQL native


Pour utiliser des requtes optimises et tirer partie des spcificits du SGBD utilis Requtes natives du noyau session.createSQLQuery("SELECT * FROM PERSON").list(); Retourne une liste dObject[] avec des valeurs scalaires pour chaque colonne de la table PERSON (i.e. retourne une table comme pour les requtes classiques JDBC) session.createSQLQuery("SELECT * FROM PERSON") .addEntity(Person.class); Retourne une liste dobjets de la classe Person

63