Télécharger la présentation
La présentation est en train de télécharger. S'il vous plaît, attendez
1
Architecture n tiers(Java EE)
Partie 1: Mapping Objet Relationnel Chapitre 4: Hibernate
2
Généralités Outil ORM ou Cadre (Framework) de persistance libre (open source) gérant la persistance des objets Java/JavaEE en base de données relationnelle [Wikipédia,Pat05] Version 3.2.x : implémentation du standard de persistance EJB 3.0 Java Persistence API (JPA) Possibilité d’être utilisé aussi bien dans un développement client lourd, que dans un environnement web léger de type Apache Tomcat ou dans un environnement J2EE complet [Wikipédia] Code SQL généré à l’exécution via des informations fournies dans un document de correspondance (mapping) XML ou des annotations
3
Différents modules Hibernate Core : API native implémentant les services de base pour la persistance Méta-données au format XML Langage HQL et interface pour écrire des requêtes Hibernate Annotations : Remplacement des fichiers XML par des annotations JDK 5.0 implémentant les annotations du standard JPA + annotations spécifiques à Hibernate
4
Objectifs d’Hibernate
Que permet de faire Hibernate ? Hibernate s’occupe du transfert des classes Java dans les tables de la base de données (et des types de données Java dans les types de données SQL) Quel avantage est apporté par Hibernate ? Il réduit de manière significative le temps de développement qui aurait été autrement perdu dans une manipulation manuelle des données via SQL et JDBC.
5
Architecture du noyau Hibernate
Fichier de configuration Version XML : hibernate.cfg.xml permettant un paramétrage plus fin Configuration par programmation
6
Architecture du noyau Hibernate
7
Architecture du noyau Hibernate
SessionFactory (org.hibernate.SessionFactory) : Cache immuable (threadsafe) des correspondances (mappings) vers une (et une seule) base de données Coûteuse à construire car implique l’analyse des fichiers de Configuration Construite à partir d’un objet Configuration Session (org.hibernate.Session) : Objet mono-threadé, à durée de vie courte, représentant une conversation entre l'application et l'entrepôt de persistance Encapsule une connexion JDBC Contient un cache des objets persistants
8
Architecture du noyau Hibernate
9
Hibernate.cfg.xml <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD 3.0//EN" " <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 name="hibernate.connection.username">root</property> <property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect
10
Hibernate.cfg.xml(suite)
<property name="hbm2ddl.auto">update</property> <property name="hibernate.show_sql">true</property> <property name="hibernate.transaction.factory_class">org.hibernate.transaction.JDBCTransactionFactory</property> <property name="current_session_context_class">thread</property> <mapping resource="contexte/Employer.hbm.xml" /> </session-factory> </hibernate-configuration>
11
Configuration d’Hibernate
Déclaration du type de document utilisé par l’analyseur syntaxique (parseur) XML pour valider le document de configuration d’après la DTD de configuration d’Hibernate : <?xml version='1.0' encoding='utf-8'?> <!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD 3.0//EN " " Paramètres de configuration nécessaires 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 name="hibernate.connection.username">root</property> <property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect
12
Configuration d’hibernate
Activation de la génération automatique des schémas de base de données - directement dans la base de données : <property name="hbm2ddl.auto">create</property> Autre valeur update Fichier de configuration (fichier de mapping) des classes persistantes : <mapping resource="contexte/Employer.hbm.xml"/>
13
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();
14
Environnement Hibernate
Bibliothèques Hibernate Core (en plus de hibernate3.jar) : antlr.jar ANTLR (Another Tool for Language Recognition) - Indispensable à l’exécution commons-collections.jar Bibliothèques du projet Apache Jakarta Commons pour manipuler les collections - Indispensable à l’exécution Jta.jar API JTA strandard – requis pour les applications s’exécutant en dehors d’un serveur d’application dom4j.jar Analyseur Syntaxique de configuration XML et de mapping - Indispensable à l’exécution log4j jar log4j.Mécanisme de log sous-jacent pouvant être utilisé par Commons Logging - Optionnel
15
Environnement Hibernate
Fichiers nécessaires avec Hibernate Core : hibernate.cfg.xml : fichier de configuration globale contenant Les paramètres de connexion à la base de données (pilote, login, mot de passe, url, etc.) Le dialecte SQL de la base de données La gestion de pool de connexions Le niveau de détails des traces etc. Pour chaque classe persistante : ClassePersistante.java : Implémentation POJO (Plain Old Java Objects) de la classe ClassePersistante.hbm.xml : Fichier XML de correspondance (mapping) ClassePersistanteHome.java : Implémentation du DAO (Data Access Object) pour l’isolation avec la couche de persistance – Optionnel
16
Classes persistantes Objets persistants implémentés sous la forme de POJO Pas d’implémentation de certaines interfaces d’héritage de classes particulières Des règles à respecter : Implémenter un constructeur sans paramètre (pouvant être privé mais de préférence accessible par le paquetage) Fournir une propriété d'identifiant (optionnel mais fortement recommandé) Implémenter des modificateurs (mutateurs - setter) et accesseurs(getter) pour chaque champ persistant
17
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; }
18
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;} }
19
Fichier de correspondance
Hibernate a besoin de savoir comment charger et stocker des objets d’une classe persistante. Le fichier de mapping indique à Hibernate à quelle table dans la base de données il doit accéder, et quelles colonnes de cette table il devra utiliser. Le fichier de mapping doit être stocké dans le même répertoire que le fichier source.
20
Employer.hbm.xml <?xml version="1.0"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" " <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>
21
Employer.hbm.xml <property name="prenom" type="java.lang.String"> <column name="prenom" /> </property> <property name="salaire" type="float"> <column name="salaire" /> </class> </hibernate-mapping>
22
Pour manipuler les objets persistantes
Ouverture d’une Session Hibernate [ Débuter une transaction] . débute une transaction ] – fortement conseillé Appliquer les opérations de Session pour interagir avec l’environnement de persistance [Valider ( commit() ) la transaction en cours] Synchroniser avec la base de données (flush) et fermer la session
23
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();}}
24
Diagramme d’états des objets d’une classe persistante
* Méthodes JPA - implémentées dans Hibernate EntityManager mais pas dans Hibernate Core
25
Contexte de persistance
Session associée à un contexte de persistance : Vérification des modifications et synchronisation avec la base de données (automatic dirty checking) Garantie de l’identité Java Extension du contexte de persistance à une conversation (unité de travail longue)
26
Contexte de persistance
Utilisation du cache : Pour vérifier les mises à jour Pour améliorer les performances en diminuant l’interaction avec la base de données Pour éviter les conflits de représentation (pas deux objets correspondants au même nuplet) Possibilité de gérer le cache (détachement d’objets et nettoyage du contexte de persistance)
27
Contexte de persistance
Opérations Session Récupérer une instance persistante Rendre une instance persistante Rendre persistantes les modifications apportées à une instance persistante Rendre persistantes les modifications apportées à une instance détachée Ré-attacher une instance détachée Détacher une instance persistante Supprimer une instance persistante Rafraîchir une instance Détecter automatiquement un état
28
Contexte de persistance
Récupérer une instance persistante dans Hibernate Core : session.load(Class cl, serializable id) ⇒ Levée d’une exception irrécupérable s'il n'y a pas de ligne correspondante dans la base de données session .get(Class cl, serializable id) ⇒ null si pas de nuplet correspondant dans la base
29
Contexte de persistance
Pour ces deux méthodes : Génération d’un ordre SQL un SELECT sur la base pour récupérer l’entité à partir de son identificateur Possibilité de charger dans une instance nouvellement créée ou dans une instance existante Possibilité de transformer le SELECT en SELECT ... FOR UPDATE en utilisant LockMode.UPGRADE en 3ème paramètre Possibilité de récupérer une instance aussi par les API Query, Criteria, SQLQuery
30
Contexte de persistance
session.save(objet) Pour rendre persistante une instance temporaire Génération d’une commande INSERT uniquement exécutée au moment du lancement de la méthode session.commit() session.persist(objet) session.merge(objet) Fusionne une instance détachée avec une instante persistante (existante ou chargée depuis la base) Effectue un SELECT avant pour déterminer s’il faut faire INSERT ou UPDATE
31
Contexte de persistance
Rendre persistante les modifications apportées à une instance persistante : ⇒ Pas de méthode particulière (automatic dirty checking) Tout modification d’une instance persistante transactionnelle (objet chargé, sauvegardé, créé ou requêté par la Session) est rendu persistant par la méthode flush() Surveillance (dirty checking) de toutes les instances persistantes par la session Instance persistante modifiée = instance sale (dirty) Synchronisation avec la base définitive une fois la transaction sous-jacente validée
32
Contexte de persistance
Rendre persistante les modifications apportées à une instance détachée : Pas de surveillance possible des instances détachées ⇒ nécessité de ré-attacher les instances en rendant persistant les modifications apportées session.merge(objet) Effectue un SELECT avant l’UPDATE pour récupérer les données dans la base et les fusionner avec les modifications apportées Retourne l’instance persistante correspondante session.update(objet) Force la mise à jour (UPDATE) de l’objet dans la base Lève une exception si une instance de même identificateur existe dans la Session
33
Contexte de persistance
Détacher une instance persistante : Plus de surveillance de l’instance par la Session : ⇒Plus aucune modification rendue persistante de manière transparente Trois moyens de détacher une instance : En fermant la session : session.close() En vidant la session : session.clear() En détachant une instance particulière: session.evict(objet)
34
Contexte de persistance
Rendre un objet transient : ⇒ Extraction définitive de l’entité correspondante dans la base de données session.delete(objet) : Enregistrement correspondant plus présent dans la base Instance toujours présente dans la JVM tant que l’objet est référencé – instance transiente
35
Correspondance des associations
Partie la plus complexe dont dépend les performances de l’application Balises de correspondance des collections : <set>, <list>; <map>, <bag>, <array> … Tags de correspondance des cardinalités/multiplicités : <one-to-one>, <many-to-one>, <many-to-many> Si correspondance d’une collection : utilisation d’une balise de collection contenant un tag de cardinalité Si correspondance d’une association uni ou bidirectionnelle vers une entité : utilisation des balises de cardinalité
36
Correspondance des associations
<many-to-one> et <one-to-one> : associations uni ou bi-directionnelle vers une entité name : nom de la propriété column : nom de la clé étrangère – possibilité de balise <column> class : nom de la classe associée – optionnel par défaut le type de la propriété déterminé par réflexion cascade : Propagation des opérations de l'objet père vers les objets associés – optionnel + d’autres – cf. doc Hibernate
37
Many-to-one Exemple d’association uni-directionnelle :
public class Enseignant { private int id ; private String nom; private float salaire; private Departement departement; Enseignant Departement 1 *
38
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"/> <many-to-one name="departement" class="persistence.Departement" > <column name="numero" not-null="true" /> </many-to-one> </class>
39
Many-to-one Pour chaque opération 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"/>
40
One-to-one La méthode la plus simple est d’utiliser est de traiter une association one-to-one comme une association many-to-one on ajoutant la contrainte unique à true Enseignant Adresse 1 1
41
One-to-one <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"/> </class></hibernate-mapping> package persistence; public class Adresse { private int numero; private String Rue; private String Ville; //Getters et setters …}
42
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>
43
One-to-One On a mappé une association one-to-one unidirectionnelle d’Enseignant vers Adresse Si on voulez transformer cette association en bidirectionnelle on devra ajouter un attribut enseignant dans la classe adresse Enseignant Adresse 1 1
44
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" />
45
One-to-One Une deuxième méthode de mapper une association One-to-one est de faire partager les deux objets(un Enseignant et une Adresse) la même clé primaire. Ici si on va choisir que l’enseignant est l’objet fort(master) et sa clé est généré automatiquement donc un objet adresse doit partager la clé de l’enseignant comme clé étrangère. Chaque objet Adresse aura la même valeur de la clé de l’enseignant.
46
One-to-One Adresse.hbm.xml Enseignant.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" />
47
Correspondance des associations
Implémentations des collections Set, List et Map propres à Hibernate Balise propre à chaque type d’interface : <set>, <list>, <map> etc. name : nom de la propriété contenant la collection table : nom de la relation contenant la collection - optionnel par défaut nom de la propriété - non utilisé pour les associations one-to-many lazy : pour désactiver l'initialisation tardive - par défaut = true inverse : Pour définir la collection comme extrémité inverse de l'association bidirectionnelle.
48
One-to-Many private Set<Enseignant> enseignants; <set name="enseignants" inverse="true" cascade="all" > <key column="id" /> <one-to-many class="Enseignant"/> </set>
49
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>
50
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>
51
Many-to-Many Ne pas oublier de gérer les deux extrémités des associations En relationnel, contrairement au Java, réalisation d’une seule opération : mise à jour ou initialisation de la clé étrangère En Java : deux opérations – une à chaque extrémité de l’association Ne pas oublier de spécifier inverse= "true" à l’une des extrémité dans le fichier de correspondance pour éviter la création de deux ordres SQL Penser à regrouper les méthodes d’instanciation au sein d’une méthode métier « de cohérence »
52
Héritage Hibernate supporte les trois stratégies d'héritage de base :
Une table par hiérarchie de classe (table per class hierarchy) Une table par classe fille (table per subclass) Une table par classe concrète (table per concrete class) Hibernate supporte en plus une quatrième stratégie, légèrement différente, qui supporte le polymorphisme : le polymorphisme implicite (Il ne sera pas étudié en cours)
53
Héritage Une table par hiérarchie 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" /> </class>
54
Héritage Une table par hiérarchie 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" /> </class>
55
Héritage 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"> <property name="capacite" type="int" column="CAPACITE" /> </class>
56
Héritage Une table par classe concrète (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"> <property name="couleur" column="COULEUR" />
57
Héritage Inconvénient majeur de cette solution est qu’un stylo et un ramette peuvent avoir la même valeur de clé primaire. Pour résoudre ce problème 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" /> </class>
58
Héritage <class name="Article" abstract="true">
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" /> </class>
59
Requête HQL "Langage de requêtes orientées objet" ou encapsulation du SQL selon une logique orientée objet Requêtes HQL (et SQL natives) représentées avec une instance de org.hibernate.Query Obtention d’une Query en utilisant la Session courante : session.createQuery (string) Clauses : from, select, where Invocation de la méthode list() ⇒ retour du résultat sous forme de liste Query req = session.createQuery("from Module"); List modules=req.list();
60
Requête HQL Interface Query fournit deux méthodes pour récupérer un sous ensemble du résultat. Très utile pour la pagination. Query req = session.createQuery("from Module"); req.setFirstResult(20);// premier enregistrement(commence par 0) req.setMaxResults(10);// nombre d’enregistrement List modules=req.list(); Avec HQL on peut ajouter des paramètres à la requête Query req = session.createQuery("from Module where id=?"); Req.setInt(0,100);
61
Requête HQL Autre méthode
Query req = session.createQuery("from Module where id=:id_m"); Req.setInt(id_m,100); List modules=req.list(); from : Clause suivie d’un 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");
62
Requête HQL join : Pour exécuter 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
63
Requête SQL native Pour utiliser des requêtes optimisées et tirer partie des spécificités du SGBD utilisé Requêtes natives du noyau session.createSQLQuery("SELECT * FROM PERSON").list(); Retourne une liste d’Object[] avec des valeurs scalaires pour chaque colonne de la table PERSON (i.e. retourne une table comme pour les requêtes classiques JDBC) session.createSQLQuery("SELECT * FROM PERSON") .addEntity(Person.class); Retourne une liste d’objets de la classe Person
Présentations similaires
© 2024 SlidePlayer.fr Inc.
All rights reserved.