Transcript hibernat
HIBERNATE
FRAMEWORK DE MAPPING
OBJET-RELATIONNEL
Riadh Ouersighni
Année 2009-2010
Architecture d'une application Java
en couches
Une application java est souvent découpée en couches. Considérons une
architecture courante, celle à trois couches :
utilisateur
Couche
Interface
Couche Métier
Couche d’accès aux
données (DAO)
1
2
3
Données
La couche [1], (User Interface) : dialogue avec l'utilisateur, via une interface
graphique Swing, une interface console ou une interface web. Elle a pour rôle de
fournir des données provenant de l'utilisateur à la couche [2] ou bien de présenter à
l'utilisateur des données fournies par la couche [2].
• La couche [2], appelée ici [metier] est la couche qui applique les règles dites
métier, c.a.d. la logique spécifique de l'application, sans se préoccuper de savoir d'où
viennent les données qu'on lui donne, ni où vont les résultats qu'elle produit.
• La couche [3], appelée ici [dao] (Data Access Object) est la couche qui fournit à la
couche [2] des données pré-enregistrées et qui enregistre certains des résultats
fournis par la couche [2].
Hibernate java
2
Couche accès aux données
Il existe différentes possibilités pour implémenter la couche Accès aux
Données
utilisateur
Couche
Interface
1
Couche Métier
2
Couche d’accès
aux données
(DAO)
Couche
JDBC
Base de
données
3
La couche [JDBC] est la couche standard utilisée en Java pour accéder à des
bases de données. Elle isole la couche [dao] du SGBD qui gère la base de
données.
Hibernate java
3
Couche HIBERNATE
De multiples efforts ont été faits pour isoler la couche [dao] des aspects propriétaires des
SGBD. Une solution qui a eu un vrai succès dans ce domaine ces dernières années, est
celle d'Hibernate
Couche d’accès
aux données
(DAO)
Objets image
de la BD
Couche
Couche
Hibernate
JDBC
BD
La couche [Hibernate] vient se placer entre la couche [dao] écrite par le développeur et
la couche [Jdbc]
Hibernate est un ORM (Object Relational Mapping), un outil qui fait le pont entre le
modèle relationnel des bases de données et celui des objets manipulés par Java
Le développeur ne voit plus la couche [Jdbc] ni les tables de la BD. Il ne voit que l'image
objet de BD, fournie par la couche [Hibernate]. Le pont entre les tables de la BD et les
objets manipulés par la couche [dao] est fait par des fichiers de configuration de type
XML
Hibernate java
4
Hibernate
Hibernate est un projet open source visant à proposer un
outil de mapping entre les objets et des données stockées
dans une base de données relationnelle. Ce projet ne repose
sur aucun standard mais il est très populaire notamment à
cause de ses bonnes performances et de son ouverture avec
de nombreuses bases de données.
Les bases de données supportées sont les principales du
marché : Oracle, MySQL, PostgreSQL, Sybase, SQLServer,
Sap DB, DB2,Interbase, ...
Le site officiel http://www.hibernate.org contient beaucoup
d'informations sur l'outil et propose de le télécharger ainsi
que sa documentation.
Hibernate java
5
Architecture Hibernate
Hibernate java
6
Principe de fonctionnement à l’aide d’un Exemple
Nous allons utiliser Hibernate avec une base de données de type MySQL
possédant une table nommée "personnes".
Créez la table
personnes dans la
BD bdperso
Hibernate a besoin de plusieurs éléments pour fonctionner :
Une classe « javabean » qui encapsule les données d'une occurrence d'une
table
Un fichier de correspondance qui configure la correspondance entre la
classe et la table
des propriétés de configuration notamment des informations concernant
la connexion à la base de données
Une fois ces éléments correctement définis, il est possible d'utiliser Hibernate
dans le code des traitements à réaliser.
Hibernate java
7
Configuration Hibernate sous NetBeans 6.1
Sous Netbeans, ajoutez le framework Hibernate :
Allez dans « tools “ + “plugins “+ “Available plugins” ,
sélectionnez Hibernate puis installez.
Créez un nouveau projet web sous NetBeans
Dans la définition du nouveau projet, cochez Framework
Hibernate
Ajoutez Mysql jdbc Driver (click droit sur Librairie puis Add)
Configuration hibernate.cfg.xml : Pour exécuter Hibernate, il faut lui
fournir un certain nombre de propriétés concernant sa configuration pour
qu'il puisse se connecter à la base de données. Ces propriétés peuvent être
fournies sous plusieurs formes :
un fichier de configuration nommé hibernate.properties et stocké dans un
répertoire inclus dans le classpath
un fichier de configuration au format XML nommé hibernate.cfg.xml
Hibernate java
8
Hibernate java
9
Nom de la BD
Hibernate java
10
Les propriétés de configuration
Les principales propriétés pour configurer la connexion JDBC sont :
Nom Propriété
Rôle
hibernate.connection.driver_class
nom pleinement qualifié de classe du pilote JDBC
hibernate.connection.url
URL JDBC désignant la base de données
hibernate.connection.username
nom de l'utilisateur pour la connexion
hibernate.connection.password
mot de passe de l'utilisateur
hibernate.connection.pool_size
nombre maximum de connexions dans le pool
Autres propriétés
Nom Propriété
Rôle
hibernate.dialect
nom de la classe pleinement qualifiée qui assure le dialogue
avec la base de données
hibernate.show_sql
booléen qui précise si les requêtes SQL générées par
Hibernate sont affichées dans la console (utile lors du
débogage)
Hibernate java
11
Le Fichier 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 name="hiSession">
<!-- dialect -->
<property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>
<!-- driver -->
<property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
<!-- host -->
<property name="hibernate.connection.url">
jdbc:mysql://localhost:3306/bdperso
</property>
<!-- username -->
<property name="hibernate.connection.username">root</property>
<!-- password to my db -->
<property name="hibernate.connection.password"/></property>
</session-factory>
</hibernate-configuration>
Hibernate java
12
Etape suivante : La création d'une classe qui va encapsuler les données
Cette classe doit respecter le standard des javabeans notamment encapsuler
les propriétés dans ces champs private avec des getters et setters et avoir un
constructeur vide.
import java.util.Date;
public class Personnes {
private Integer idPersonne;
private String nomPersonne;
private String prenomPersonne;
private Date datenaissPersonne;
public Personnes(String nomPersonne, String prenomPersonne, Date
datenaissPersonne) {
this.nomPersonne = nomPersonne;
this.prenomPersonne = prenomPersonne;
this.datenaissPersonne = datenaissPersonne;
}
public Personnes()
{
}
Pour ajouter les Getters et les Setters : click droit puis choisir « Insert code »
Netbeans génère automatiquement les méthodes get et set
Hibernate java
13
Clic droit ici
Hibernate java
14
Etape suivante : Mapping : La création d'un fichier de
correspondance
Pour assurer le mapping, Hibernate a besoin d'un fichier de correspondance
(mapping file) au format XML qui va contenir des informations sur la
correspondance entre la classe définie et la table de la base de données.
Le plus simple est de définir un fichier de mapping par classe, nommé du
nom de la classe suivi par ".hbm.xml".
Ce fichier doit être situé dans le même répertoire que la classe
correspondante ou dans la même archive pour les applications packagées.
Dans notre projet Netbeans :
Click droit / new / other / hibernate / hibernate mapping file / OK
Différents éléments sont précisés dans ce document XML :
la classe qui va encapsuler les données
l'identifiant dans la base de données et son mode de génération
le mapping entre les propriétés de classe et les champs de la base de données
les relations
Hibernate java
15
Hibernate java
16
Hibernate java
17
Hibernate java
18
Hibernate java
19
<?xml version="1.0"?><!DOCTYPE hibernate-mapping
PUBLIC "-//Hibernate/Hibernate Mapping DTD 2.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-2.0.dtd">
<hibernate-mapping>
<class name="Personnes" table="personnes">
<id name="idPersonne" type="int" column="idpersonne">
<generator class="native"/>
</id>
<property name="nomPersonne" type="string" not-null="true" />
<property name="prenomPersonne" type="string" not-null="true" />
<property name="datenaissPersonne" type="date">
<meta attribute="field-description">date de naissance</meta>
</property>
</class>
</hibernate-mapping>
Hibernate java
20
Le tag <class> permet de préciser des informations sur la classe qui va
encapsuler les données.
Ce tag possède plusieurs attributs dont les principaux sont:
Nom
Obligatoire
rôle
name
oui
Nom de la classe
table
oui
Nom de la table dans la Base de donnée
dynamic- non
update
booléen qui indique de ne mettre à jour que les champs
dont la valeur a été modifiée (false par défaut)
dynamic- non
insert
booléen qui indique de générer un ordre insert que pour les
champs dont la valeur est non nulle (false par défaut)
Le tag <generator>, fils obligatoire du tag <id>, permet de préciser quel
est le mode de génération d'un nouvel identifiant.
Ce tag possède un attribut : class (obligatoire) qui précise la classe qui
va assurer la génération de la valeur d'un nouvel identifiant. Il existe
plusieurs classes fournies en standard par Hibernate qui possèdent un
nom utilisable comme valeur de cet attribut.
Hibernate java
21
Les classes de génération fournies en standard par Hibernate
possèdent chacun un nom :
Nom
Rôle
increment
incrémentation d'une valeur dans la JVM
identify
utilisation d'un identifiant auto-incrémenté pour les bases de données qui le
supportent (DB2, MySQL,SQL Server, ...)
sequence
utilisation d'une séquence pour les bases de données qui le supportent (Oracle, DB2,
PostgreSQL, ...)
hilo
utilisation d'un algorithme qui utilise une valeur réservée pour une table d'une base de
données (par exemple une table qui stocke la valeur du prochain identifiant pour
chaque table)
seqhilo
idem mais avec un mécanisme proche d'une séquence
uuid.hex
utilisation d'un algorithme générant un identifiant sur 32 caractères prenant en
compte entre autre l'adresse IP de la machine et l'heure du système
uuid.string
idem générant un identifiant sur 16 caractères
native
utilise la meilleure solution proposée par la base de données
assigned
la valeur est fournie par l'application
foreign
la valeur est fournie par un autre objet avec lequel la classe est associée
Hibernate java
22
Hibernate doit savoir qu’est ce qu’il “mappe”
Ajouter ce code au fichier xml “hibernate.cfg.xml”
<mapping class=“Personnes" resource=“Personnes.hbm.xml"/>
Hibernate java
23
Utilisation d'Hibernate
Pour utiliser Hibernate dans le code, il est nécessaire de
réaliser plusieurs opérations :
création d'une instance de la classe
création d'une instance de la classe SessionFactory
création d'une instance de la classe Session qui va permettre
d'utiliser les services d'Hibernate
Hibernate java
24
Si les propriétés sont définies dans le fichier
hibernate.properties, il faut tout d'abord créer une instance de
la classe Configuration. Pour lui associer la ou les classes
encapsulant les données, la classe propose deux méthodes :
1. addFile() qui attend en paramètre le nom du fichier de
mapping
2. addClass() qui attend en paramètre un objet de type Class
encapsulant la classe. Dans ce cas, la méthode va
rechercher un fichier nommé nom_de_la_classe.hbm.xml
dans le classpath (ce fichier doit se situé dans le même
répertoire que le fichier .class de la classe correspondante)
Hibernate java
25
Une instance de la classe Session est obtenu à partir d'une
fabrique de type SessionFactory.
Cet objet est obtenu à partir de l'instance du type Configuration
en utilisant la méthode buildSessionFactory().
La méthode openSession() de la classe SessionFactory permet
d'obtenir une instance de la classe Session.
Par défaut, la méthode openSession() qui va ouvrir une
connexion vers la base de données en utilisant les informations
fournies par les propriétés de configuration.
Hibernate java
26
Exemple :
import net.sf.hibernate.*;
import net.sf.hibernate.cfg.Configuration;
import java.util.Date;
public class TestHibernate1 {
public static void main(String args[]) throws Exception {
Configuration config = new Configuration();
config.addClass(Personnes.class);
SessionFactory sessionFactory =
config.buildSessionFactory();
Session session = sessionFactory.openSession();
….
Hibernate java
27
Le fichier “HibernateUtil.java” permet de créer le “session factory “ . Il
faut créer une nouvelle classe
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
public class HibernateUtil {
private static final SessionFactory sessionFactory;
static {
try {
//Create the SessionFactory
sessionFactory = new Configuration().configure("hibernate.cfg.xml").buildSessionFactory();
} catch (Throwable ex) {
// Log the Exception
System.err.println("SessionFactory creation failed!!!" + ex);
throw new ExceptionInInitializerError(ex);
}
}
public static SessionFactory getSessionFactory() {
return sessionFactory;
}
}
Hibernate java
28
La persistance d'une nouvelle occurrence
Pour créer une nouvelle occurrence dans la source de
données, il suffit de :
créer une nouvelle instance de classe encapsulant les
données,
de valoriser ces propriétés
et d'appeler la méthode save() de la session en lui
passant en paramètre l'objet encapsulant les données.
La méthode save() n'a aucune action directe sur la base de
données.
Pour enregistrer les données dans la base, il faut
réaliser un commit sur la connexion ou la transaction ou
faire appel à la méthode flush() de la classe Session.
Voir exemple de code suivant :
Hibernate java
29
import net.sf.hibernate.*;
import net.sf.hibernate.cfg.Configuration;
import java.util.Date;
public class TestHibernate1 {
public static void main(String args[]) throws Exception {
Configuration config = new Configuration();
config.addClass(Personnes.class);
SessionFactory sessionFactory = config.buildSessionFactory();
Session session = sessionFactory.openSession();
Transaction tx = null;
try {
tx = session.beginTransaction();
Personnes personne = new Personnes("nom3", "prenom3", new Date());
session.save(personne);
session.flush() ;
tx.commit();
} catch (Exception e) {
if (tx != null) {
tx.rollback();
}
throw e;
} finally {
session.close();
}
sessionFactory.close();
}
}
Hibernate java
30
Le langage de requête HQL
Pour offrir un langage d'interrogation commun à toutes les
base de données, Hibernate propose son propre langage
nommé HQL (Hibernate Query Language)
HQL est proche de SQL avec une utilisation sous forme
d'objets des noms de certaines entités : il n'y a aucune
référence aux tables ou aux champs car ceux ci sont
référencés respectivement par leur classe et leurs propriétés.
C'est Hibernate qui se charge de générer la requête SQL à
partir de la requête HQL en tenant compte du contexte (type
de base de données utilisée défini dans le fichier de
configuration et la configuration du mapping).
Hibernate java
31
La méthode find() de la classe Session permet d'effectuer une
recherche d'occurrences grâce à la requête fournie en paramètre.
Exemple : rechercher toutes les occurrences d'une table
import net.sf.hibernate.*;
import net.sf.hibernate.cfg.Configuration;
import java.util.*;
public class TestHibernate3 {
public static void main(String args[]) throws Exception {
Configuration config = new Configuration();
config.addClass(Personnes.class);
SessionFactory sessionFactory = config.buildSessionFactory();
Session session = sessionFactory.openSession();
try {
List personnes = session.find("from Personnes");
for (int i = 0; i < personnes.size(); i++) {
Personnes personne = (Personnes) personnes.get(i);
System.out.println("nom = " + personne.getNomPersonne());
}
} finally {
session.close();
}sessionFactory.close();
Hibernate java
}}
32
import net.sf.hibernate.*;
import net.sf.hibernate.cfg.Configuration;
import java.util.*;
public class TestHibernate4 {
public static void main(String args[]) throws Exception {
Configuration config = new Configuration();
config.addClass(Personnes.class);
SessionFactory sessionFactory = config.buildSessionFactory();
Session session = sessionFactory.openSession();
try {
List personnes = session.find("from Personnes p where p.nomPersonne=?","nom1",
Hibernate.STRING);
for (int i = 0; i < personnes.size(); i++) {
Personnes personne = (Personnes) personnes.get(i);
System.out.println("nom = " + personne.getNomPersonne());
}
} finally {
session.close();
}
sessionFactory.close();
}
}
Hibernate java
33
import net.sf.hibernate.*;
import net.sf.hibernate.cfg.Configuration;
import java.util.*;
public class TestHibernate5 {
public static void main(String args[]) throws Exception {
Configuration config = new Configuration();
config.addClass(Personnes.class);
SessionFactory sessionFactory = config.buildSessionFactory();
Session session = sessionFactory.openSession();
try {
int compteur = ( (Integer) session.iterate("select count(*) from
Personnes").next()).intValue();
System.out.println("compteur = " + compteur);
} finally {
session.close();
sessionFactory.close();
}
}
}
Hibernate java
34
La mise à jour d'une occurrence
Pour mettre à jour une occurrence dans la source de données,
il suffit d'appeler la méthode update() de la session en lui
passant en paramètre l'objet encapsulant les données.
Le mode de fonctionnement de cette méthode est similaire à
celui de la méthode save().
La méthode saveOrUpdate() laisse Hibernate choisir entre
l'utilisation de la méthode save() ou update() en fonction de la
valeur de l'identifiant dans la classe encapsulant les données.
Hibernate java
35
La suppression d'une ou plusieurs occurrences
La méthode delete() de la classe Session permet de
supprimer une ou plusieurs occurrences en fonction de la
version surchargée de la méthode utilisée.
Pour supprimer une occurrence encapsulée dans une classe,
il suffit d'invoquer la classe en lui passant en paramètre
l'instance de la classe.
Pour supprimer plusieurs occurrences, voire toutes, il faut
passer en paramètre de la méthode delete(), une chaîne de
caractères contenant la requête HQL pour préciser les
éléments concernés par la suppression.
Exemple
session.delete("from Personnes");
Hibernate java
36
Les relations
Un des fondements du modèle de données relationnelles
repose sur les relations qui peuvent intervenir entre une table
et une ou plusieurs autres tables ou la table elle même.
Hibernate propose de transcrire ces relations du modèle
relationnel dans le modèle objet. Il supporte plusieurs types de
relations :
•relation de type 1 - 1 (one-to-one)
•relation de type 1 - n (many-to-one)
•relation de type n - n (many-to-many)
Dans le fichier de mapping, il est nécessaire de définir les
relations entre la table concernée et les tables avec lesquelles
elle possède des relations.
Hibernate java
37