Entity - e
Transcription
Entity - e
JAVA PERSISTENCE API Jean-Jacques LE COZ Introduction Historique Le manque de solutions a freiné l'utilisation des langages orientés objet dans les entreprises Notamment pour les applications de gestion Les intergiciels Type ODBC ou JDBC Trop bas niveau Ne masquent pas la non correspondance des paradigmes objet et relationnel Solutions Récentes, fin des années 90 Produits de mapping O/R Persistance des objets Frameworks de mapping O/R Persistance des objets Outils Conception du mapping Classes persistantes Tables de la base de données Standardisation Pour la plateforme Java JPA (Standard Java Persistence API) Pour les platefomes C++, .NET, Python Aucun standard Plateforme Java JPA Sources de données relationnelles Convergence entre JDO et EJB Versions J2EE EJB3 et JDO 2 JDO Java Data Object Interface de programmation universelle Toutes les sources de données Relationnelles, Objets, Transactionnelles, XML, ... Outils pour Java (1) Au standard JPA Produits commerciaux TopLink (Oracle : contributeur de l'implémentation de référence) Produits libres Hibernate (Communauté libre Hibernate) GlassFish (Sun Micro-system) Outils pour Java (2) Au standard JDO Produits commerciaux Kodo JDO (SolarMetric) Implémentation de référence JDO1(Sun Microsystems) Open Access JDO (Versant Corporation) LiDO (Xcalia) Produits libres JODInstruments Speedo Triactive JDO XORM JPOX (Implémentation de référence JDO2) Outils pour Java (3) Non standardisés Commerciaux CocoBase (Thought Inc) Nombreux autres produits Libres Castor Cayenne (en cours de standardisation JPA) iBatis Hibernate Produit phare pour Java Hibernate Enorme succès Tous les types d'entreprise Tous les types d'application Nombreuses ressources Documentations Livres Retours d'expérience Site officiel www.hibernate.org Hibernate Produit Open Source Licence LGPL Supporte tous les SGBDR du marché Solution orthogonale Supporte tous les concepts objets Héritage Polymorphisme Composition Supporte les transactions Hibernate pourquoi faire ? Pour les architectures Applications Web Applications distribuées Pour les disponibilités Forte montée en charge Transactions longues Solution industrielle Versions du logiciel Hibernate Versions antérieures à 3.1 Solution propriétaire Versions postérieures à 3.1 Standardisée JPA JPA avec HIBERNATE État des objets persistants Trois états possibles Transient Persistant Objet nouvellement créé Objet transient sauvé ou objet retrouvé Détaché Objet persistant hors d'une session hibernate Peut être ré-attaché Cycle de vie des objets Identité JPA Chaque objet persistant possède deux identités : Identité Java OID affecté à l'objet par la JVM Identité JPA ID affecté à l'objet par HIBENRATE Correspond à une valeur de clef primaire dans la base de données Verrouillage Optimiste Garantie la montée en charge Basé sur le comportement du SGBDR multiversion concrrency control Numérotation des versions Estampille Pessimiste Verrouillage explicite Adaptation aux possibilités du SGBDR Verrouillage optimiste Gestion au niveau applicatif Gestion automatique Objets détachés Sessions longues Personnalisation Verrouillage pessimiste Lecture Écriture Mise-à-jour Performances Seulement 10% moins rapide que JDBC Options de gestion des performances Lazy initialisation + objets proxies Caches Cache par défaut Premier niveau de cache Niveau session Caches supplémentaires Second niveau de cache Niveau application Pour les résultats des requêtes Compromis Limiter le nombre d'entrées/sorties Ici les requêtes SQL Solution par anté-mémoires (caches) Limiter l'encombrement mémoire Ici les caches Solution par lecture incrémentale Stratégies de chargement Deux principes Quand est fait le chargement Immédiatement (eager) Tardivement (lazy) Comment est fait le chargement Par jointure Par multiple requêtes Objets mandataires (1) Les proxys HIBERNATE Supportent le polymorphisme Utilisés pour les relations Un vers plusieurs Un vers un Avec le type de chargement tardif (lazy) Pour chaque objet dépendant Charge uniquement son ID hibernate et sa version Crée un objet proxy avec ces deux caractéristiques Objets mandataires (2) Les proxys HIBERNATE Créés dynamiquement à l'exécution Par manipulation du Byte Code Java Par spécialisation de la classe de l'objet Quand une invocation arrive sur l'objet chargement de l'objet Délégation entre le proxy et l'objet Développer au standard JPA Introduction Basé sur J2SE version 5 Pas besoin de fichiers de mapping XML « bootsrap » d'une application JPA La classe EntityManager Stanard JPA et EJB3 Basé sur les nouveautés Java Tiger (Java 5) Annotations Java 5 Syntaxe : @uneAnnotation Compatibilité EJB3 Exemple @Entity public class Etudiant { ... Fichier technique Le fichier persistence.xml Déploiement Dans le répertoire META-INF Déclaration des classes persistantes Paramétrage de la connexion JDBC Déclaration du pool de connexions JDBC Options Exemple de persistence.xml <?xml version="1.0" encoding="UTF-8"?> <persistence> <persistence-unit name="manageur" transaction-type="RESOURCE_LOCAL"> <class>modele.Etudiant</class> <class>modele.Promotion</class> <properties> <property name="hibernate.dialect" value="org.hibernate.dialect.PostgreSQLDialect"/> <property name="hibernate.connection.driver_class" value="org.postgresql.Driver"/> <property name="hibernate.connection.username" value="postgres"/> <property name="hibernate.connection.password" value="jjlcoz"/> <property name="hibernate.connection.url" value="jdbc:postgresql://localhost/hibernate01"/> <property name="hibernate.max_fetch_depth" value="3"/> <!-- création du schéma automatiquement --> <property name="hibernate.hbm2ddl.auto" value="create-drop"/> </properties> </persistence-unit> </persistence> Une classe persistante Une classe POJO persistante Annotation @Entity Mapping vers une relation @Table(name=''matable'') Identité JPA @Id Correspond à une clef primaire non composée Peut être une sequence ou une identity (clef auto-incrémentée) @GeneratedValue Exemple de classe persistante @Entity @Table(name="TAB_ETUDIANT") public class Etudiant { private int id; private String nom; private String prenom; private String adresse; public Etudiant(String nom, String prenom, String adresse) { this.setNom(nom); this.setPrenom(prenom); this.setAdresse(adresse); } @Id @GeneratedValue public int getId() { return id; } public void setId(int id) {this.id = id; } ... Les clefs surrogate Annotation générale @GeneratedValue Stratégies AUTO Option par défaut La couche de persistance choisit une des stratégies suivantes TABLE IDENTITY SEQUENCE Stratégie de génération de clef TABLE SEQUENCE La couche de persistance utilise une table pour gérer la génération elle-même La couche de persistance utilise une séquence de la base de données pour la génération IDENTITY La couche de persistance se repose entièrement sur base de données pour la gestion de la génération Exemple SEQUENCE @Entity @SequenceGenrator(name=''LA_TABLE_DE_SEQUENCES'', sequenceName=''MA_SEQUENCE'', initialValue=1, allocationSize=10) public class MaClasse { ... @Id @GeneratedValue(strategy=GenerationType.SEQUENCE, generator=''LA_TABLE_DE_SEQUENCE'') public int getId() { .... Exemple IDENTITY @Id @GeneratedValue(strategy=GenerationType.IDENTITY) @Column(name=''MACLEF'') public Long getId() { .... Propriétés Propriétés non persistantes Annotation @Transient Propriétés persistantes Par défaut Annotation @Basic Permet d'associer une stratégie de chargement @Basic(fetch = FetchType.LAZY ou EAGER) Propriétés gros grains Fichiers BLOB, CLOB BLOB (Binary Large Object) java.sql.Blob, Byte[ ], byte[ ] Types serializable CLOB (Characters Large Object) java.sql.Clob, Character[ ], char[ ], String Annotation @Lob Mapping propriété/colonne Déclaré sur la méthode get... Annotation @Column Attributs name, unique, nullable, insertable, updatable length, precision, scale Exemple @Column(name=CODE,nullable=false,unique=true) Gestion des transactions Par l'objet EntityManager Avec Java SE Obtenu par un EntityManagerFactory A partir de l'interface Persistence Dans les environnements gérés Obtenu par injection Annotation @PersistenceContext Utilisation des classes public static void main(String[] args) { EntityManagerFactory emf = Persistence.createEntityManagerFactory("manageur", new HashMap()); EntityManager em = emf.createEntityManager(); em.getTransaction().begin(); Promotion mod7 = new Promotion("MOD7",new Date(), new Date()); Etudiant e1 = new Etudiant("Dupont","Jacques","PARIS"); Etudiant e2 = new Etudiant("Martin","Pierre","LILLE"); Etudiant e3 = new Etudiant("Abellard","Sophie","LYON"); mod7.addEtudiant(e1); mod7.addEtudiant(e2); mod7.addEtudiant(e3); em.persist(mod7); em.getTransaction().commit(); em.close(); emf.close(); } Les relations Relations Tous les types de relation entre objets sont supportés Mono-directionnelles Bi-directionnelles Multiplicités Toutes les multiplicités sont supportées Cardinalités 1,1 – 1,1 1,1 – 1,N @OneToOne @ManyToOne et @OneToMany 1,N – 1,N @ManyToMany Génération de schéma Relations @OneToOne et @OneToMany Possibilité de relation directe entre tables avec clef(s) étrangère(s) @JoinColumn Possibilité de table associative Relation @ManyToMany Effectuée avec une table associative Relations mono-directionnelles Maître et esclave de la relation La relation mono-directionnelle ne détermine que le rôle maître ou possesseur de la relation C'est le côté maître d'une relation qui détermine les mises à jour dans la base de données Synchronisation Cascade Modèle UML Exemple avec OneToMany @Entity @Table(name="PROMOTION") public class Promotion { ... private Collection<Etudiant> etudiants; ... @OneToMany(cascade=CascadeType.ALL) @JoinColumn(name="PROMOTION_ID") public Collection<Etudiant> getEtudiants() { return etudiants; } ... Modèle UML Exemple avec ManyToOne @Entity @Table(name="ETUDIANT") public class Etudiant { ... private Promotion promotion; ... @ManyToOne public Promotion getPromotion() { return promotion; } ... Relations bi-directionnelles Maître et esclave de la relation Côté inverse de la relation (esclave) Doit définir l'attribut mappedBy La donnée membre pointée par mappedBy est une propriété de la classe persistante maîtresse (possesseur) de la relation Côté possesseur (maître) Côté Many d'une relation ManyToOne Côté(s) Many d'une relation ManyToMany Côté contenant la clef étrangère d'une relation OneToOne Modèle UML Exemple avec OneToMany @Entity @Table(name="PROMOTION") public class Promotion { ... private Collection<Etudiant> etudiants; ... @OneToMany(mappedBy=''promotion'', cascade=CascadeType.ALL) public Collection<Etudiant> getEtudiants() {return etudiants; } ... Exemple avec ManyToOne @Entity @Table(name="ETUDIANT") public class Etudiant { ... private Promotion promotion; ... @ManyToOne public Promotion getPromotion() { return promotion; } ... Persistance par navigation Persistance transitive Opérations propagées Attribut cascade Associé à un tableau de types de cascade CascadeType Le type ALL Tous les types sont associés CascadeType.ALL Les types de cascade Types CascadeType.PERSIST CascadeType.MERGE CascadeType.REMOVE Persistance par navigation Suppression en cascade (cascade delete) CascadeType.REFRESH Clefs primaires composées Clefs primaires composées (1) Les clés composées doivent être implémentées par des classes Les classes de clés primaires doivent implémentées l'interface Serializable Elles doivent implémenter aussi La méthode hashCode() La méthode equals() Clefs primaires composées (2) Annotation spécifique pour les classes clef primaire composée @Embeddable Définitions d'un classe clef pour une classe persistante Annotation @IdClass Annotation @EmbededId Exemple de clé primaire @Embeddable public class ParlerPK implements Serializable { private static final long serialVersionUID = 1L; private int etudiantid; private int langueid; public int getEtudiantid() {return etudiantid;} public void setEtudiantid(int etudiantid) {this.etudiantid = etudiantid;} public int getLangueid() {return langueid;} public void setLangueid(int langueid) {this.langueid = langueid;} } Exemple de classe avec clé @Entity @Table(name="PARLER") @IdClass(ParlerPK.class) public class Parler { private static final long serialVersionUID = 1L; private int etudiantid; private int langueid; private Etudiant etudiant; private Langue langue; private double note; ... Spécialisation Modèle UML Types d'implémentation Une table par classe Annotation Une table pour toute la hiérarchie Annotation @Inheritance(strategy = InheritanceType.JOINED) @Inheritance(strategy = InheritanceType.SINGLE_TABLE) Une table par sous-classe concrète Annotation @Inheritance(strategy = InheritanceType.TABLE_PER_CLASS) Une table par classe Cette stratégie d'implémentation supporte les relations de type 1 vers N si elles sont bidirectionnelles Cette stratégie ne supporte pas IDENTITY L'identifiant doit être partagé entre les tables Donc pas de possibilité de AUTO pour les « sous-tables » Une table par hiérarchie Distinction du type des instances Par discriminant Annotations @DiscriminatorColumn( name="nom du type" discriminatorType=DiscriminatorType.STRING @DiscriminatorValue("valeur") Implémenter par une colonne supplémentaire dans la table Une table par sous-classe Les tables sont jointes par une même clef primaire Annotation @PrimaryKeyJoinColumn(name="nom clef") Héritage de propriétés A partir d'une classe non mappée @MappedSuperclass public class EntiteDeBase { @Basic @Temporal(TemporalType.TIMESTAMP) public Date getDerniereMAJ() { ... } public String getCommercial() { ... } ... } @Entity class Commande extends EntiteDeBase { @Id public Integer getId() { ... } ... } Réécriture de propriétés @MappedSuperclass public class FlyingObject { public int getAltitude() { return altitude; } @Transient public int getMetricAltitude() { return metricAltitude; } ... } @Entity @AttributeOverride( name="altitude", column=@Column(name="fld_altitude") ) public class Plane extends FlyingObject { ... } Bibliographie Hibernate in Action – Manning Pro Hibernate 3 – Apress Professional Hibernate – Wrox Hibernate : A Developer's Notebook – O'Reilly Java Data Objects – O'Reilly Core Java Data Objects – Prentice Hall Using and Understanding Java Data Objects - Apress