1. Université Tunis El Manar Faculté des Sciences de Tunis Département des Sciences de l’Informatique Encadré par : M. Sadok Ben Yahia Réalisé par : Megadmini Maher (étudiant I4) La persistance des données avec Hibernate Année universitaire 2008/2009 Cours Web et Base de données
2.
3.
4. Motivation L’Objet est devenu le style fondamentale de la programmation Base de données OO Développement Conception Langage orienté objet: java c# c++... UML O2, EyeBD Peu mature, peu expérimentée Coût de migration BDR vers BDOO Comment faire correspondance entre O/R BD Relationnelle ? :-/ ? ? 4
7. ORM c’est quoi? Le mapping objet relationnel crée une illusion d’une BDOO à partir d’une BDR public class Obj { private int id; private String name; public Obj(){ } public Obj(String name) { this.name = name; } public void setId(int i) { id = i; } …. } Il existe plusieurs Framework de mapping objet/relationnel : Java Persistance API, TopLink, Java Data Object, Hibernate, Object Relational Bridge… Donc on peut bénéficier de l’orienté objet et gérer une BD relationnelle d’une façon transparente. 7 .. … .. … .. .. name Id
8.
9. Hibernate : Framework de mapping O/R Il a été développé par un groupe de développeurs Java dirigés par Gavin King POJO: Plain Old Java Object « bon vieil objet java » : une classe de type javabean qui doit encapsuler les propriétés dans des champs private avec des getters et setters et avoir au moins un constructeur sans paramètre Tables Relationnelles Différents propriétés de configuration : connexion, url de la BD, Dialect utilisé… Le mapping est assuré par des fichiers XML Hibernate est un Framework open source gérant la persistance des objets en base de données relationnelle. 9
12. package persistClass; public class Matiere { private String nom ; private Integer codeMat ; public Matiere(){} public Matiere(Integer code,String nom) { this . nom = nom; this . codeMat =code; } public String getNom() { return nom ; } public void setNom(String nom) { this . nom = nom; } public Integer getCodeMat() { return codeMat ; } public void setCodeMat(Integer code) { this . codeMat = code; } } <? 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 > < class name = "persistClass.Matiere" table = "matiere" > < id name = "codeMat" type = "int" column = "code_mat" ></ id > < property name = "nom" type = "string" length = "50" column = "nom_mat" /> </ class > </ hibernate-mapping > - Ce fichier xml sera sauvegardé sous le nom Matiere.hbm.xml et dans le même répertoire que son POJO correspondant. - On peut aussi mapper tous les POJO dans un seul fichier. 12 package POJO attribut Clé primaire
13.
14.
15.
16. public class Etudiant extends Personne { private float moy ; public Etudiant(){} public Etudiant(Integer cin,String nom,String prenom){ super (cin,nom,prenom); } //Getters and Setters } public class Prof extends Personne { private String grade ; public Prof(){} public Prof(Integer cin,String nom,String prenom,String grade){ super (cin,nom,prenom); this . grade =grade; } //Getters and Setters } public class Personne { private Integer cin ; private String nom ; private String prenom ; public Personne(){ } public Personne(Integer cin,String nom,String prenom) { this . cin = cin; this . nom =nom; this . prenom =prenom; } //Getters and Setters } Personne( cin , nom, prenom) Prof( cin# , grade) Etudiant( cin# , moy_et) Hibernate offre différents stratégies pour mapper l’héritage: - <subclass> - <union-subclass> - <joined-subclass> 16
17. < class name = "persistClass.Personne" table = "personne" > < id name = "cin" type = "int" column = "cin_pers" ></ id > < property name = "nom" type = "string" length = "50" column = "nom_pers" /> < property name = "prenom" type = "string" length = "50" column = "prenom_pers" /> < joined-subclass name = "persistClass.Etudiant" table = "etudiant" > < key column = "cin" /> < property name = "moyenne" type = "float" column = "moy_et" /> </ joined-subclass > < joined-subclass name = "persistClass.Prof" table = "prof" > < key column = "cin" /> < property name = "grade" type = "string" column = "grade" /> </ joined-subclass > </ class > 17 Identifiants hérités Clés référencées Attributs propres aux classes filles
18. Relation plusieurs à plusieurs « many to many » Assurer la navigabilité: - on peut consulter et maj. l’ensemble des matières d’une filière donnée - on peut consulter dans quelles filières est étudiée une matière donnée et maj. cet ensemble de filières public class Filiere { … private Set mats = new HashSet(); public Set getMats() { return mats ; } public void setMats(Set mats) { this . mats = mats; } } fil1.getMats().add(mat1); fil1.getMats().remove(mat3); Le bon fonctionnement des Set (ou autre collection) nécessite la redéfinition de la méthode hashCode() 18
19. Relation plusieurs à plusieurs « many to many » < set name = "mats" table = "mat_fil" cascade = "all" > < key column = "code_fil" /> < many-to-many column = "code_mat" class = "persistClass.Matiere" /> </ set > cascade (optionnel - par défaut = none) : active les opérations de cascade vers les entités filles cascade="all | none | save-update | delete | all-delete-orphan" 19 La nouvelle table du à la relation « many to many » Cette table n’a pas besoin d’être mapper ou représenté par une POJO sauf dans le cas ou elle contient autre propriétés que les deux clés étrangères. On mappe la classe Matiere de la même façon (en changeant le nécessaire) pour avoir une relation bidirectionnelle.
20. La relation est bidirectionnelle: - Une filière pour plusieurs étudiants : Relation un à plusieurs « one to many » - Plusieurs étudiants pour une filière : Relation plusieurs à un « many to one » public class Etudiant extends Personne { … private Filiere fil ; //Getter and Setter … } public class Filiere { … private Set etds = new HashSet(); public Set getEtds() { return etds ; } public void setEtds(Set etds) { this . etds = etds; } public void addEtds(Etudiant et){ et.setFil( this ); this .getEtds().add(et); }} Optimisation du code 20
21. < set name = "etds" inverse = "true" cascade = "all" > < key column = "fil_affect" /> < one-to-many class = "persistClass.Etudiant" /> </ set > < joined-subclass name = "persistClass.Etudiant" table = "etudiant" > … < many-to-one name = "fil" column = "fil_affect" /> </ joined-subclass > inverse (optionnel - par défaut = false) : définit cette collection comme l'extrémité "inverse" de l'association bidirectionnelle 21
22. POJO XML Mapping Schéma relationnel Middlegen ShemaExport hbm2ddl XDoclet CodeGenerator hbm2java Trop de code à écrire? Hibernate vous facilite la tâche et met en disposition le package Hibernate tools (ensemble d’outils de génération avec Ant) 22
23.
24. On peut configurer hibernate soit par un fichier hibernate.properties soit par un fichier XML hibernate.cfg.xml soit par programmation. Configuration Dans la configuration on doit indiquer à Hibernate: - les SessionFactory de notre application (une fabrique de session responsable d’une base de données) Avec une SessionFactory on peut : - Configurer l’accès à la BD (driver, url, login, pw…) - Configurer le pool de connexion (nombre min-max des connexions, temps d’inactivité max pour une connexion…) 24
25. <? 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 = "connection.driver_class" > com.mysql.jdbc.Driver </ property > < property name = "connection.url" > jdbc:mysql://localhost:3306/exphib </ property > < property name = "connection.username" > root </ property > < property name = "connection.password" ></ property > < property name = "connection.pool_size" > 1 </ property > < property name = "dialect" > org.hibernate.dialect.MySQLDialect </ property > < property name = "current_session_context_class" > thread </ property > < property name = "cache.provider_class" > org.hibernate.cache.NoCacheProvider </ property > < property name = "show_sql" > true </ property > < property name = "hbm2ddl.auto" > create </ property > < mapping resource = "persistClass/Personne.hbm.xml" /> < mapping resource = "persistClass/Matiere.hbm.xml" /> < mapping resource = "persistClass/Filiere.hbm.xml" /> </ session-factory > </ hibernate-configuration > La SessionFactory de notre unique base Configuration de la connexion avec la base (driver, url, login, mot de passe..) Configuration de pool de connexion Indication du Dialect Configuration de cache Afficher les requêtes SQL sur la console Génération automatique de la base (drop if exist) Fichiers XML de mapping 25
26.
27. La SessionFactory nous permet d’ouvrir des sessions et des transactions import persistClass.*; import org.hibernate.*; import persistance.HibernateUtil; public class Tester { public static void main(String[] args) { //ouvrir une session Session session1 = HibernateUtil. getSessionFactory ().openSession(); //commencer une transaction Transaction tx1 = session1.beginTransaction(); //consulter modifier la base //fermer la transaction tx1.commit(); //fermer la session session1.close(); }} 27
28.
29. Les requêtes Hibernate permet l’exécution des requêtes SQL standard. Hibernate s'occupera du mapping des résultats vers des objets. Exemple: List mats = session1.createSQLQuery( "select * from matiere" ) .addEntity(Matiere. class ) .list(); Float max = (Float) session1.createSQLQuery( "select max(etudiant.moy_et) as moy from etudiant e" ) .addScalar( "moy" , Hibernate. FLOAT ) .uniqueResult(); 29
30. Les requêtes Hibernate fournit un langage d'interrogation extrêmement puissant qui ressemble au SQL. HQL (Hibernate Query Language) est totalement orienté objet, comprenant des notions d'héritage, de polymorphisme et d'association. Les éléments que l'ont spécifie font parti de l'objet persistant, et non de la base de donnée. Pour bien comprendre Hibernate, il faut raisonner en Objet et pas en terme de SGBD relationnel. « www.labo-sun.com » Exemple: List pers = session1.createQuery( "select * from Personne where Personne.name = ?" ) .setString(0, "ali" ) .List(); 30
31. Les requêtes Hibernate offre la possibilité de créer des requêtes dynamiquement à travers l’API Criteria. Criteria permet de requêter la base selon un critère de recherche donnée. Exemple: session1.createCriteria(Filiere. class ) .add( Expression.like( "nom" , "sciences%" ) ); Criteria crit = session1.createCriteria(Personne. class ); crit.addOrder( Order.asc( "name" ) ); List results = crit.list(); List etudiant = session1.createCriteria(Etudiant. class ) .add(Restrictions. between ( "code" , new Integer(100), new Integer(199))) .list(); 31
32. 32 La classe Session permet à travers ses différents méthodes de manipuler la persistance des objets. List personnes = session.find( "from Personne p where p.nom=?" , "ali" , Hibernate. STRING ); int compteur = ( (Integer) session.iterate( "select count(*) from Personnes" ).next() ).intValue(); int pers = session.delete( "from Personne p where p.nom=?" , "ali" , Hibernate. STRING ); Personne pers = (Personne) sess.load(Personne. class , new Integer(21)); Exemple:
33. Les objets que manipule une application peuvent passer par différents états. Un objet est dit persistant s’il est au moins sauvegardé dans le cache Après d’être détaché d’une transaction Un objet est éphémère (passager) s’il n’est pas encore lié à une transaction ou bien supprimé de la base 33
34.
35. Mise en œuvre de l’exemple La classe qui contient notre main() La classe qui contient notre SessionFactory() Nos POJO XML de Mapping Fichiers de configuration de Hibernate Fichier Log similaire à celui d’un SGBD Il affiche les messages des traces sur la console. Les différents .jar pour assurer le fonctionnement de Hibernate Le driver de la base 35