28/02/2012
Framework de persistance
Hibernate
BOUSETTA Ibrahim
MOR
Les difficultés de cohabitation entre les
mondes objets et relationnels sont
résolues grâce au concept de Mapping
objet-relationnel (O/R Mapping)
Ce terme (ORM) décrit la technique
consistant à faire le lien entre la
représentation objet des données et sa
représentation relationnelle, basé sur un
schéma SQL.
1
28/02/2012
Architecture Multi-niveaux
Séparation des couches
3 BOUSETTA Brahim
Frameworks de persistance
Outils permettant de :
modéliser un système de données,(UML ou en XML), et de
générer tous les DAO ainsi que les objets métiers.
De plus, ils prennent en charge des concepts avancés
comme :
le cache des objets,
la concurrence,
les transactions distribuées,
le chargement des données via des requêtes objets, et
peuvent également offrir une totale indépendance vis-à-vis du
serveur de bases de données.
Ils créent des systèmes complètement autonomes de
gestion du système d’information, autorisent un fort
découplage avec la base de données, améliorent les
performances et apportent 4une grande simplicité
BOUSETTA Brahim
d’utilisation.
2
28/02/2012
Hibernate
Hibernate est un framework puissant de
Java qui permet la persistance des objets.
Hibernate est un projet open source, libre
et employé couramment par les sociétés.
Hibernate est un framework de mapping
objet relationnel ou objet persistent.
En effet, l’application voit la couche
d’accès aux données comme des objets
qui seront sauvegardés après que
l’application soit éteinte.
5 BOUSETTA Brahim
vue d'ensemble générale de
l'architecture d’Hibernate
6 BOUSETTA Brahim
3
28/02/2012
7 BOUSETTA Brahim
Les fichiers de mapping xml
Comme beaucoup de frameworks J2EE, Hibernate
est configuré par des fichiers xml.
Le fichier de mapping mappe les tables de la base
de données.
L’application lira ce fichier pour créer les objets à
partir de la base de données.
Exemple d’une classe Catalogue .
8 BOUSETTA Brahim
4
28/02/2012
class Catalogue
public class Catalogue {
private int numCat;
private String desCat;
private ArrayList<Article> articles;
public Catalogue(int numCat, String desCat, ArrayList<Article>
articles) {
super();
this.numCat = numCat;
this.desCat = desCat;
this.articles = articles;
}
}
9 BOUSETTA Brahim
class Article
public class Article {
private int idA;
private String descA;
private double prix;
Getters et setters
}
5
28/02/2012
Le fichier de mapping xml
(MaClasse.hbm.xml)
<!DOCTYPE hibernate-mapping PUBLIC "-
//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-
3.0.dtd">
<hibernate-mapping>
…..
</hibernate-mapping>
Les éléments des fichiers de mapping Hibernate
contiennent les propriétés des classes persistantes
liant les objets et les tables de la base de données.
Voici le mapping correspondant à la classe Account :
11 BOUSETTA Brahim
Article.hbm
<hibernate-mapping package="caisse.bo">
<class name="Article" table="ARTICLE">
<id column="IDARTICLE" name="idA" type="integer" >
<generator class="sequence" />
</id>
<property column="PRIX" length="5" name="prix" not-
null="false" type="float" />
<property column="LIBELLE" length="50" name="descA"
not-null="false" type="string"
/>
</class>
</hibernate-mapping>
6
28/02/2012
Catalogue.hbm.xml
<hibernate-mapping package="caisse.bo">
<class name="Catalogue" table="CATALOGUE">
<id column="NUMCAT" name="Numcat" type="integer" >
<generator class="sequence" />
</id>
<property column="DESCAT" length="50" name="Descat"
not-null="false" type="string" />
<set inverse="false" lazy="true" name="articles" >
<key column="NUMCAT" />
<one-to-many class="Article" />
</set>
</class>
</hibernate-mapping>
13 BOUSETTA Brahim
The Hibernate configuration file
On dois configurer Hibernate avec la source de
données.
Pour la configuration d'Hibernate on peut employer :
un simple fichier hibernate.properties,
un fichier hibernate.cfg.xml ou
nous pouvons faire la configuration dans le code.
J'emploierai un fichier hibernate.cfg.xml pour faire la
configuration.
Exemple de Hibernate avec la base de données
PostgreSQL.
Les pilotes JDBC PostgreSQL peuvent être téléchargés sur :
http://jdbc.postgresql.org/download.html.
Les fichiers jar sont à inclure dans le dossier contenant toutes
les librairies et a ajouter au class path de l’application.
14 BOUSETTA Brahim
7
28/02/2012
The Hibernate configuration file
<hibernate-configuration>
<session-factory>
<property name="hibernate.connection.url">
jdbc:oracle:thin:@localhost:1521:XE </property>
<property name="hibernate.connection.driver_class">
oracle.jdbc.driver.OracleDriver </property>
<property
name="hibernate.connection.username">caisse2</property>
<property name="hibernate.connection.password">
caisse2</property>
<property name="dialect"> org.hibernate.dialect.OracleDialect
</property>
<mapping resource="caisse/bo/Catalogue.hbm" />
<mapping resource="caisse/bo/Article.hbm" />
</session-factory>
</hibernate-configuration>
15 BOUSETTA Brahim
Session Factory
public class HibernateUtil {
public static Session currentSession() throws HibernateException
{
Session session = null;
try {
Configuration cfg = new Configuration();
cfg.configure("/hibernate.cfg.xml");
SessionFactory sessionFactory = cfg.buildSessionFactory();
session = sessionFactory.openSession() ;
} catch (Exception e) {
System.err.println(e.getMessage());
e.printStackTrace();
}
return session;
}
} 16 BOUSETTA Brahim
8
28/02/2012
Lister les données :
public static void main(String[] args) {
Session session = HibernateUtil.currentSession();
List<Article> arts = session.createQuery("select a from
Article a ").list();
for(Article a:arts)
System.out.println(a.getDescA());
Session (org.hibernate.Session)
C’est un objet à durée de vie courte qui
représente une conversation entre l'application et
l'entrepôt de persistance. Il encapsule une
connexion JDBC.
Hibernate définit et comprend les états suivants :
Éphémère (NdT : transient) - un objet est éphémère
s'il a juste été instancié en utilisant l'opérateur new. Il
n'a aucune représentation persistante dans la base
de données et aucune valeur d'identifiant n'a été
assignée.
Persistant - une instance persistante a une
représentation dans la base de données et une valeur
d'identifiant.
Détaché - une instance détachée est un objet qui a
été persistant, mais dont sa Session a été fermée.
18 BOUSETTA Brahim
9
28/02/2012
Rendre un objet persistant : insertion
Les instances nouvellement instanciées d'une classe
persistante sont considérées éphémères par Hibernate.
Nous pouvons rendre une instance éphémère persistante en
l'associant avec une session :
Article a= new Article(100,"desca",200);
session.beginTransaction();
Integer generatedId =(Integer)session.save(a);
//ou encore session.save(a, new Integer(100));
session.getTransaction().commit();
generatedId permet de récupérer l’id affecté à
l’articlecourant
19 BOUSETTA Brahim
Chargement d'un objet
Les méthodes load() de Session vous donnent un moyen de
récupérer une instance persistante si vous connaissez déjà son
identifiant.
load() prend un objet de classe et chargera l'état dans une
instance nouvellement instanciée de cette classe, dans un état
persistant.
art = (Article ) session.load(Article.class, generatedId);
Alternativement, vous pouvez charger un état dans une instance
donnée :
Article a = new Article ();
session.load( a, new Long(pkId) );
Si vous n'êtes pas certain qu'une ligne correspondante existe,
vous devriez utiliser la méthode get(), laquelle accède à la base
de données immédiatement et retourne null s'il n'y a pas de ligne
correspondante.
Article a = (Article ) session.get(Article .class, id);
20 BOUSETTA Brahim
10
28/02/2012
Il est possible de re-charger un objet et toutes ses
collections à n'importe quel moment, en utilisant la
méthode refresh(). C'est utile lorsque des "triggers"
de base de données sont utilisés pour initialiser
certains propriétés de l'objet.
session.save(Article );
session.flush(); //force the SQL INSERT
session.refresh(Article ); //re-read the state (after
the trigger executes)
Session.flush() permet de s’assurer que les
changements sont synchronisés avec la base de
données.
Cependant, si vous utilisez une Transaction, l'appel de
la méthode commit() l'appellera automatiquement.
21 BOUSETTA Brahim
Modifier des objets persistants
Les instances persistantes transactionnelles
(c'est-à-dire des objets chargés, sauvegardés,
créés ou requêtés par la Session) peuvent être
manipulées par l'application et n'importe quel
changement vers l'état persistant sera persisté
lorsque la Session est "flushée" .
Article a = (Article ) sess.load(Article .class, new Integer(1) );
cat.setLibelle("Produit xxx");
sess.flush(); // changes to cat are automatically detected and persisted
22 BOUSETTA Brahim
11
28/02/2012
Suppression d'objets persistants
Session.delete() supprimera l'état d'un objet de la
base de données.
Bien sûr, votre application pourrait encore conserver
une référence vers un objet effacé.
Il est mieux de penser à delete() comme rendant une
instance persistante éphémère.
session.delete(art);
Vous pouvez effacer des objets dans l'ordre que vous
voulez, sans risque de violations de contrainte de clef
étrangère.
Il est encore possible de violer une contrainte NOT
NULL sur une colonne de clef étrangère en effaçant
des objets dans le mauvais ordre, par exemple si vous
effacer le parent, mais oubliez d'effacer les enfants.
23 BOUSETTA Brahim
Article a3=(Article)session.load(Article.class, new
Integer(32));
System.out.println(a3.getIdA()+"--"+a3.getDescA());
a3.setDescA("new desc");
Session.flush();
a3=(Article)session.load(Article.class, new Integer(32));
System.out.println(a3.getIdA()+"--"+a3.getDescA());
session.delete(a3);
12
28/02/2012
Hibernate Annotations
Configuration
Tout d'abord, paramétrez votre classpath (après
avoir créer un nouveau projet dans votre IDE
favori) :
Copiez toutes les bibliothèques du noyau
Hibernate3 et toutes les bibliothèques tierces
requises (voir lib/README.txt dans Hibernate).
Copiez aussi hibernate-annotations.jar et
lib/ejb3-persistence.jar de la distribution
Hibernate Annotations dans votre classpath.
13
28/02/2012
Fichier de configuration
Il est le meme que pour le mapping classique avec les fichier xml.
Les balises <mapping resource="…"/>
<mapping resource="caisse/bo/Catalogue.hbm" />
<mapping resource="caisse/bo/Article.hbm" />
Seront remplacées par :
<session-factory>
<mapping package="test.bo"/>
<mapping class="test.bo.Article"/>
<mapping class="test.bo.Catalogue"/>
</session-factory>
Le mapping de classe peut etre omis dans le fichier de
configuration et défini à la creation de session factory avec les
methode s:
.addPackage("metier.bo")
.addAnnotatedClass(metier.bo.Salarie.class)
[email protected] BOUSETTA Ibrahim
Session Factory
public static Session getSession() throws HibernateException {
SessionFactory sessionFactory = new
AnnotationConfiguration().configure("/hibernate.cfg.xml")
.addPackage(“metier.bo")
.addAnnotatedClass(metier.bo.Salarie.class)
.addAnnotatedClass(metier.bo.Article.class)
.addAnnotatedClass(metier.bo.TypeArticle.class)
//….
.buildSessionFactory();
return sessionFactory.openSession();
}
14
28/02/2012
Entity Beans
@Entity déclare la classe comme un entity bean,
@Id déclare la propriété identifiante de cet entity bean.
Les autres déclarations de mapping sont implicites.
Ce concept de déclaration par exception est un composant
essentiel de la nouvelle spécification EJB3 et une
amélioration majeure.
La classe Article est mappée sur la table Article, en utilisant
la colonne id comme colonne de la clef primaire.
@Entity
public class Article {
@Id
private int idA;
private String desc;
…
}
[email protected] BOUSETTA Ibrahim
Définir la table :
@Table est positionnée au niveau de la classe ; cela vous
permet de définir le nom de la table, du catalogue et du
schéma pour le mapping de votre entity bean.
Si aucune @Table n'est définie les valeurs par défaut sont
utilisées : le nom de la classe de l'entité (sans le nom de
package).
//@Table(name="Article")
public class Article {
L'élément @Table contient aussi un attribut schema et un
attribut catalog, si vous avez besoin de les définir.
Vous pouvez aussi définir des contraintes d'unicité sur la
table en utilisant l'annotation @UniqueConstraint en
conjonction avec @Table (pour une contrainte d'unicité
n'impliquant qu'une seule colonne, référez-vous à
@Column).
[email protected] BOUSETTA Ibrahim
15
28/02/2012
Mapping de simples propriétés
Chaque propriété (champ ou méthode) non statique non
transient d'un entity bean est considérée persistante, à
Entity Beans moins que vous l'annotiez comme @Transient.
Ne pas avoir d'annotation pour votre propriété est
équivalent à l'annotation @Basic. L'annotation @Basic vous
permet de déclarer la stratégie de récupération pour une
propriété :
public class Caisse {
@Id
private int idCaisse;
@Basic
private String descr;
@Transient
private Vente ventecourante=null;
Déclarer des attributs de colonne
@Entity
public class Flight {
...
@Column(updatable = false, name = "flight_name", nullable
= false, length=50)
private String name;
…
@Column(
name="columnName";
boolean unique() default false;
boolean nullable() default true;
boolean insertable() default true;
boolean updatable() default true;
String table() default ""; (
int length() default 255;
int precision() default 0; // decimal precision (9)
[email protected] BOUSETTA Ibrahim
16
28/02/2012
Mapper des propriétés identifiantes
L'annotation @Id vous permet de définir quelle propriété identifie votre
entity bean. Cette propriété peut être positionnée par l'application elle-
même ou générée par Hibernate (préféré).
Vous pouvez définir la stratégie de génération de l'identifiant grâce à
l'annotation @GeneratedValue :
AUTO - soit la colonne identity, soit la séquence, soit la table selon la
base de données sous-jacente
TABLE - table contenant l'id
IDENTITY - colonne identity
SEQUENCE - séquence
@Entity
@javax.persistence.SequenceGenerator( name="seqc",
sequenceName="seq_c" )
@Table(name="caisse")
public class Caisse {
@Id @GeneratedValue(strategy=GenerationType.SEQUENCE,
generator="seqc")
private int idCaisse;
[email protected] BOUSETTA Ibrahim
Mapper l'héritage
EJB3 prend en charge les trois types d'héritage :
Stratégie d'une table par classe concrète : l'élément
<union-class> dans Hibernate
Stratégie d'une seule table par hiérarchie de classe :
l'élément <subclass> dans Hibernate
Stratégie d'une table par classe fille : l'élément <joined-
subclass> dans Hibernate
La stratégie choisie est déclarée au niveau de la classe de
l'entité la plus haute dans la hiérarhie en utilisant
l'annotation @Inheritance.
17
28/02/2012
@Entity
@Inheritance(strategy=InheritanceType.JOINED)
public abstract class Salarie implements Serializable {
@Id
private int matricule;
….
}
@Entity
@PrimaryKeyJoinColumn(name="matricule")
public class Caissier extends Salarie{
…
}
Mapper des associatiion
One-to-one
@Entity
@PrimaryKeyJoinColumn(name="matricule")
public class Caissier extends Salarie{
@OneToOne(cascade = CascadeType.ALL)
@JoinColumn(name="idcaisse")
private Caisse caisse;
….
@Entity
public class Caisse {
@Id
private int idCaisse;
@OneToOne(mappedBy = "caisse")
private Caissier caissier;
18
28/02/2012
Many-to-one
public class LigneVente {
@Id
private int idLV;
@ManyToOne( cascade = {CascadeType.PERSIST,
CascadeType.MERGE,CascadeType.REMOVE} )
@JoinColumn(name="numvente")
private Vente vente;
@ManyToOne( cascade = {CascadeType.PERSIST,
CascadeType.MERGE,CascadeType.ALL} )
@JoinColumn(name="idarticle")
private Article article;
One-to-Many
public class Vente {
@Id
@Column(name="numVente")
private int numV;
@ManyToOne( cascade = {CascadeType.PERSIST,
CascadeType.MERGE} )
@JoinColumn(name="idCaisse")
private Caisse caisse;
@OneToMany(mappedBy="vente", cascade = {CascadeType.PERSIST,
CascadeType.MERGE, CascadeType.ALL})
private List<LigneVente> Lventes;
19
28/02/2012
Many-to-Many
@Entity
public class Auteur {
@ManyToMany( targetEntity=Livre.class,
cascade={CascadeType.PERSIST, CascadeType.MERGE})
@JoinTable( name="Ecrire", joinColumns=@JoinColumn(name="idA"),
inverseJoinColumns=@JoinColumn(name="ISBN") )
private List<Livre> livres;
...
}
@Entity
public class Livre {
@ManyToMany( cascade = {CascadeType.PERSIST,
CascadeType.MERGE},
mappedBy = "livres", targetEntity = Auteur.class
)
private List<Auteur> auteurs;
}
[email protected] BOUSETTA Ibrahim
20