Vous êtes sur la page 1sur 105

24/04/2017 DvelopponsenJavaHibernate

Dveloppons
RecherchedansDEJavecGoogle Rechercher
en Java v
4 2.10
Copyright (C) 1999-
2016 Jean-Michel
DOUDOUX.

54. Hibernate

Niveau : Suprieur

Hibernate est une solution open source de type ORM (Object Relational Mapping) qui permet de faciliter le dveloppement de la couche persistance
d'une application. Hibernate permet donc de reprsenter une base de donnes en objets Java et vice versa.

Hibernate facilite la persistence et la recherche de donnes dans une base de donnes en ralisant lui-mme la cration des objets et les traitements
de remplissage de ceux-ci en accdant la base de donnes. La quantit de code ainsi pargne est trs importante d'autant que ce code est
gnralement fastidieux et redondant.

Hibernate est trs populaire notamment cause de ses bonnes performances et de son ouverture de nombreuses bases de donnes.

Les bases de donnes supportes sont les principales du march: DB2, Oracle, MySQL, PostgreSQL, Sybase, SQL Server, Sap DB, Interbase, ...

Le site officiel http://www.hibernate.org contient beaucoup d'informations sur l'outil et propose de le tlcharger ainsi que sa documentation.

La version utilise dans cette section est la 2.1.2 : il faut donc tlcharger le fichier hibernate-2.1.2.zip et le dcompresser dans un rpertoire du
systme.

Ce chapitre va utiliser Hibernate avec une base de donnes de type MySQL possdant une table nomme "personnes".

Hibernate a besoin de plusieurs lments pour fonctionner:

une classe de type javabean qui encapsule les donnes d'une occurrence d'une table
un fichier de configuration qui assure la correspondance entre la classe et la table (mapping)
des proprits de configuration notamment des informations concernant la connexion la base de donnes

Une fois ces lments correctement dfinis, il est possible d'utiliser Hibernate dans le code des traitements raliser. L'architecture d'Hibernate est
donc la suivante:

https://www.jmdoudoux.fr/java/dej/chaphibernate.htm 1/105
24/04/2017 DvelopponsenJavaHibernate
Ce chapitre survole uniquement les principales fonctionnalits d'Hibernate qui est un outil vraiment complet: pour de plus amples informations, il est
ncessaire de consulter la documentation officielle fournie avec l'outil ou consultable sur le site web.

Ce chapitre contient plusieurs sections :

La cration d'une classe qui va encapsuler les donnes


La cration d'un fichier de correspondance
Les proprits de configuration
L'utilisation d'Hibernate
La persistance d'une nouvelle occurrence
L'obtention d'une occurrence partir de son identifiant
L'obtention de donnes
La mise jour d'une occurrence
La suppression d'une ou plusieurs occurrences
Les relations
Le mapping de l'hritage de classes
Les caches d'Hibernate
Les outils de gnration de code

54.1. La cration d'une classe qui va encapsuler les donnes


Cette classe doit respecter le standard des Javabeans, notamment, encapsuler les proprits dans ses champs private avec des getters et setters et
avoir un constructeur par dfaut.

Les types utilisables pour les proprits sont: les types primitifs, les classes String et Dates, les wrappers, et n'importe quelle classe qui encapsule une
autre table ou une partie de la table.

Exemple :

01. importjava.util.Date;
02.
03. publicclassPersonnes{
04.
05. privateIntegeridPersonne;
06. privateStringnomPersonne;
07. privateStringprenomPersonne;
08. privateDatedatenaissPersonne;
09.
10. publicPersonnes(StringnomPersonne,StringprenomPersonne,DatedatenaissPersonne){
11. this.nomPersonne=nomPersonne;
12. this.prenomPersonne=prenomPersonne;
13. this.datenaissPersonne=datenaissPersonne;
14. }
15.
16. publicPersonnes(){
17. }
18.
19. publicDategetDatenaissPersonne(){
20. returndatenaissPersonne;
21. }
22.
23. publicIntegergetIdPersonne(){
24. returnidPersonne;
25. }
26.
27. publicStringgetNomPersonne(){
28. returnnomPersonne;
29. }
30.
31. publicStringgetPrenomPersonne(){
32. returnprenomPersonne;
33. }
34.
35. publicvoidsetDatenaissPersonne(Datedate){
36. datenaissPersonne=date;
37. }
38.
39. publicvoidsetIdPersonne(Integerinteger){
40. idPersonne=integer;
41. }
42.
43. publicvoidsetNomPersonne(Stringstring){
44. nomPersonne=string;
45. }
46.
47. publicvoidsetPrenomPersonne(Stringstring){
48. prenomPersonne=string;
49. }
50.
51. }

https://www.jmdoudoux.fr/java/dej/chaphibernate.htm 2/105
24/04/2017 DvelopponsenJavaHibernate

54.2. La cration 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 dfinie et la table de la base de donnes.

Mme si cela est possible, il n'est pas recommand de dfinir un fichier de mapping pour plusieurs classes. Le plus simple est de dfinir un fichier de
mapping par classe, nomm du nom de la classe suivi par ".hbm.xml". Ce fichier doit tre situ dans le mme rpertoire que la classe correspondante ou
dans la mme archive pour les applications packages.

Diffrents lments sont prcissdans ce document XML :

la classe qui va encapsuler les donnes


l'identifiant dans la base de donnes et son mode de gnration
le mapping entre les proprits de classe et les champs de la base de donnes
les relations
...

Le fichier dbute par un prologue et une dfinition de la DTD utilise par le fichier XML.

Exemple :

1. <?xmlversion="1.0"?>
2. <!DOCTYPEhibernatemapping
3. PUBLIC"//Hibernate/HibernateMappingDTD2.0//EN"
4. "http://hibernate.sourceforge.net/hibernatemapping2.0.dtd">

Le tag racine du document XML est le tag <hibernate-mapping>. Ce tag peut contenir un ou plusieurs tag <class> : il est cependant prfrable de
n'utiliser qu'un seul tag <class> et de dfinir autant de fichiers de correspondance que de classes.

Exemple:

Exemple :

01. <?xmlversion="1.0"?><!DOCTYPEhibernatemapping
02. PUBLIC"//Hibernate/HibernateMappingDTD2.0//EN"
03. "http://hibernate.sourceforge.net/hibernatemapping2.0.dtd"><hibernatemapping>
04. <classname="Personnes"table="personnes">
05. <idname="idPersonne"type="int"column="idpersonne">
06. <generatorclass="native"/>
07. </id>
08. <propertyname="nomPersonne"type="string"notnull="true"/>
09. <propertyname="prenomPersonne"type="string"notnull="true"/>
10. <propertyname="datenaissPersonne"type="date">
11. <metaattribute="fielddescription">datedenaissance</meta>
12. </property>
13. </class>
14. </hibernatemapping>

Le tag <class> permet de prciser des informations sur la classe qui va encapsuler les donnes.

Ce tag possde plusieurs attributsdont les principaux sont:

Nom Obligatoire Rle

name oui nom pleinement qualifi de la classe

table oui nom de la table dans la base de donnes

dynamic-update non boolen qui indique de ne mettre jour que les champs dont la valeur a t modifie (false par dfaut)

dynamic-insert non boolen qui indique de ne gnrer un ordre insert que pour les champs dont la valeur est non nulle (false par dfaut)

mutable non boolen qui indique si les occurrences peuvent tre mises jour (true par dfaut)

Le tag enfant <id> du tag <class> permet de fournir des informations sur l'identifiant d'une occurrence dans la table.

Ce tag possde plusieurs attributs:

Nom Obligatoire Rle

name non nom de la proprit dans la classe

type non le type Hibernate

column non le nom du champ dans la base de donnes (par dfaut le nom de la proprit)

unsaved- non permet de prciser la valeur de l'identifiant pour une instance non encore enregistre dans la base de donnes. Les valeurs
value possibles sont : any, none, null ou une valeur fournie. Null est la valeur par dfaut.

https://www.jmdoudoux.fr/java/dej/chaphibernate.htm 3/105
24/04/2017 DvelopponsenJavaHibernate

Le tag <generator>, fils obligatoire du tag <id>, permet de prciser quel est le mode de gnration d'un nouvel identifiant.

Ce tag possde un attribut:

Attribut Obligatoire Rle

class oui prcise la classe qui va assurer la gnration de la valeur d'un nouvel identifiant. Il existe plusieurs classes fournies en
standard par Hibernate qui possdent un nom utilisable comme valeur de cet attribut.

Les classes de gnration fournies en standard par Hibernate possdent chacun un nom:

Nom Rle

increment incrmentation d'une valeur dans la JVM

identity utilisation d'un identifiant auto-incrment pour les bases de donnes qui le supportent (DB2, MySQL, SQL Server, ...)

sequence utilisation d'une squence pour les bases de donnes qui le supportent (Oracle, DB2, PostgreSQL, ...)

hilo utilisation d'un algorithme qui utilise une valeur rserve pour une table d'une base de donnes (par exemple une table qui stocke la
valeur du prochain identifiant pour chaque table)

seqhilo idem mais avec un mcanisme proche d'une squence

uuid.hex utilisation d'un algorithme gnrant un identifiant de type UUID sur 32 caractres prenant en compte entre autres l'adresse IP de la
machine et l'heure du systme

uuid.string idem gnrant un identifiant de type UUID sur 16 caractres

native utilise la meilleure solution propose par la base de donnes

assigned la valeur est fournie par l'application

foreign la valeur est fournie par un autre objet avec lequel la classe est associe

Certains modes de gnration ncessitent des paramtres: dans ce cas, il faut les dfinir en utilisant un tag fils <param> pour chaque paramtre.

Le tag <property>, fils du tag <class>, permet de fournir des informations sur une proprit et sa correspondance avec un champ dans la base de
donnes.

Ce tag possde plusieurs attributs dont les principaux sont:

Nom Obligatoire Rle

name oui prcise le nom de la proprit

type non prcise le type

column non prcise le nom du champ dans la base de donnes (par dfaut le nom de la proprit)

update non prcise si le champ est mis jour lors d'une opration SQL de type update (par dfaut true)

insert non prcise si le champ est mis jour lors d'une opration SQL de type insert (par dfaut true)

Le type doit tre soit un type Hibernate (integer, string, date, timestamp, ...), soit les types primitif Java ou de certaines classes de base (int,
java.lang.String, float, java.util.Date, ...), soit une classe qui encapsule des donnes rendre persistantes.

Le fichier de correspondance peut aussi contenir une description des relations qui existent avec la table dans la base de donnes.

54.3. Les proprits de configuration


Pour excuter Hibernate, il faut lui fournir un certain nombre de proprits concernant sa configuration pour qu'il puisse se connecter la base de
donnes.

Ces proprits peuvent tre fournies sous plusieurs formes:

un fichier de configuration nomm hibernate.properties et stock dans un rpertoire inclus dans le classpath
un fichier de configuration au format XML nomm hibernate.cfg.xml
utiliser la mthode setProperties() de la classe Configuration
dfinir des proprits dans la JVM en utilisant l'option -Dproprit=valeur

Les principales proprits pour configurer la connexion JDBC sont:

Nom de la proprit Rle

hibernate.connection.driver_class nom pleinement qualifi de la classe du pilote JDBC

https://www.jmdoudoux.fr/java/dej/chaphibernate.htm 4/105
24/04/2017 DvelopponsenJavaHibernate
hibernate.connection.url URL JDBC dsignant la base de donnes

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

Les principales proprits utiliser pour configurer une source de donnes (DataSource) sont :

Nom de la proprit Rle

hibernate.connection.datasource nom du DataSource enregistr dans JNDI

hibernate.jndi.url URL du fournisseur JNDI

hibernate.jndi.class classe pleinement qualifie de type InitialContextFactory permettant l'accs JNDI

hibernate.connection.username nom de l'utilisateur de la base de donnes

hibernate.connection.password mot de passe de l'utilisateur

Les principales autres proprits sont :

Nom de la proprit Rle

hibernate.dialect nom de la classe pleinement qualifi qui assure le dialogue avec la base de donnes

hibernate.jdbc.use_scrollable_resultset boolen qui permet le parcours dans les deux sens pour les connexions fournies Hibernate utilisant des
pilotes JDBC 2 supportant cette fonctionnalit

hibernate.show_sql boolen qui prcise si les requtes SQL gnres par Hibernate sont affiches dans la console
(particulirement utile lors du dbogage)

Hibernate propose des classes qui hritent de la classe Dialect pour chaque base de donnes supporte. C'est le nom de la classe correspondant la
base de donnes utilise qui doit tre obligatoirement fourni la proprit hibernate.dialect.

Pour dfinir les proprits utiles, le plus simple est de dfinir un fichier de configuration qui en standard doit se nommer hibernate.properties. Ce
fichier contient une paire cl=valeur pour chaque proprit dfinie.

Exemple : paramtres pour utiliser une base de donnes MySQL

1. hibernate.dialect=net.sf.hibernate.dialect.MySQLDialect
2. hibernate.connection.driver_class=com.mysql.jdbc.Driver
3. hibernate.connection.url=jdbc:mysql://localhost/testDB
4. hibernate.connection.username=root
5. hibernate.connection.password=

Le pilote de la base de donnes utilise, mysql-connector-java-3.0.11-stable-bin.jar dans l'exemple, doit tre ajout dans le classpath.

Il est aussi possible de dfinir les proprits dans un fichier au format XML nomm en standard hibernate.cfg.xml

Les proprits sont alors dfinies par un tag <property>. Le nom de la proprit est dfinie grce l'attribut name et sa valeur est fournie dans le
corps du tag.

Exemple :

01. <?xmlversion='1.0'encoding='utf8'?>
02. <!DOCTYPEhibernateconfigurationPUBLIC"//Hibernate/HibernateConfigurationDTD2.0//EN"
03. "http://hibernate.sourceforge.net/hibernateconfiguration2.0.dtd">
04. <hibernateconfiguration>
05. <sessionfactory>
06. <propertyname="hibernate.dialect">net.sf.hibernate.dialect.MySQLDialect</property>
07. <propertyname="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
08. <propertyname="hibernate.connection.url">jdbc:mysql://localhost/testDB<;/property>
09. <propertyname="hibernate.connection.username">root</property>
10. <propertyname="hibernate.connection.password"></property>
11. <propertyname="dialect">net.sf.hibernate.dialect.MySQLDialect</property>
12. <propertyname="show_sql">true</property>
13. <mappingresource="Personnes.hbm.xml"/>
14. </sessionfactory>
15. </hibernateconfiguration>

54.4. L'utilisation d'Hibernate

https://www.jmdoudoux.fr/java/dej/chaphibernate.htm 5/105
24/04/2017 DvelopponsenJavaHibernate
Pour utiliser Hibernate dans le code, il est ncessaire de raliser plusieurs oprations:

cration d'une instance de la classe


cration d'une instance de la classe SessionFactory
cration d'une instance de la classe Session qui va permettre d'utiliser les services d'Hibernate

Si les proprits sont dfinies dans le fichier hibernate.properties, il faut tout d'abord crer une instance de la classe Configuration. Pour lui associer
la ou les classes encapsulant les donnes, la classe propose deux mthodes:

addFile() qui attend en paramtre le nom du fichier de mapping


addClass() qui attend en paramtre un objet de type Class encapsulant la classe. Dans ce cas, la mthode va rechercher un fichier nomm
nom_de_la_classe.hbm.xml dans le classpath (ce fichier doit se situer dans le mme rpertoire que le fichier .class de la classe correspondante)

Une instance de la classe Session est obtenue partir d'une fabrique de type SessionFactory, elle-mme obtenue partir de l'instance du type
Configuration en utilisant la mthode buildSessionFactory().

La mthode openSession() de la classe SessionFactory permet d'obtenir une instance de la classe Session.

Par dfaut, c'est la mthode openSession() qui va ouvrir une connexion vers la base de donnes en utilisant les informations fournies par les proprits
de configuration.

Exemple :

01. importnet.sf.hibernate.*;
02. importnet.sf.hibernate.cfg.Configuration;
03. importjava.util.Date;
04.
05. publicclassTestHibernate1{
06.
07. publicstaticvoidmain(Stringargs[])throwsException{
08. Configurationconfig=newConfiguration();
09. config.addClass(Personnes.class);
10. SessionFactorysessionFactory=config.buildSessionFactory();
11. Sessionsession=sessionFactory.openSession();
12. ...

Il est aussi possible de fournir en paramtre de la mthode openSession() une instance de la classe javax.sql.Connection qui encapsule la connexion la
base de donnes.

Pour une utilisation du fichier hibernate.cfg.xml, il faut crer une occurrence de la classe Configuration, appeler sa mthode configure() qui va lire le
fichier XML et appeler la mthode buildSessionFactory() de l'objet renvoy par la mthode configure().

Exemple :

1. importnet.sf.hibernate.*;
2. importnet.sf.hibernate.cfg.Configuration;
3. importjava.util.*;
4.
5. publicclassTestHibernate1{
6. publicstaticvoidmain(Stringargs[])throwsException{
7. SessionFactorysessionFactory=newConfiguration().configure().buildSessionFactory();
8. ...

Il est important de clturer l'objet Session, une fois que celui-ci est devenu inutile, en utilisant la mthode close().

54.5. La persistance d'une nouvelle occurrence


Pour crer une nouvelle occurrence dans la source de donnes, il suffit de crer une nouvelle instance de la classe encapsulant les donnes, de valoriser
ses proprits et d'appeler la mthode save() de la session en lui passant en paramtre l'objet encapsulant les donnes.

La mthode save() n'a aucune action directe sur la base de donnes. Pour enregistrer les donnes dans la base, il faut raliser un commit sur la
connexion ou la transaction ou faire appel la mthode flush() de la classe Session.

Exemple :

01. importnet.sf.hibernate.*;
02. importnet.sf.hibernate.cfg.Configuration;
03. importjava.util.Date;
04.
05. publicclassTestHibernate1{
06.
07. publicstaticvoidmain(Stringargs[])throwsException{
08. Configurationconfig=newConfiguration();
09. config.addClass(Personnes.class);
10. SessionFactorysessionFactory=config.buildSessionFactory();
11. Sessionsession=sessionFactory.openSession();
12.
13. Transactiontx=null;
https://www.jmdoudoux.fr/java/dej/chaphibernate.htm 6/105
24/04/2017 DvelopponsenJavaHibernate
13. Transactiontx=null;
14. try{
15. tx=session.beginTransaction();
16. Personnespersonne=newPersonnes("nom3","prenom3",newDate());
17. session.save(personne);
18. session.flush();
19. tx.commit();
20. }catch(Exceptione){
21. if(tx!=null){
22. tx.rollback();
23. }
24. throwe;
25. }finally{
26. session.close();
27. }
28.
29. sessionFactory.close();
30. }
31. }

Rsultat :

01. C:\java\test\testhibernate>antTestHibernate1
02. Buildfile:build.xml
03. init:
04. [copy]Copying1filetoC:\java\test\testhibernate\bin
05. compile:
06. TestHibernate1:
07. [java]12:41:37,402INFOEnvironment:462Hibernate2.1.2
08. [java]12:41:37,422INFOEnvironment:496loadedpropertiesfromresource
09. hibernate.properties:{hibernate.connection.username=root,hibernate.connection
10. .password=,hibernate.cglib.use_reflection_optimizer=true,hibernate.dialect=net
11. .sf.hibernate.dialect.MySQLDialect,hibernate.connection.url=jdbc:mysql://localh
12. ost/testDB,hibernate.connection.driver_class=com.mysql.jdbc.Driver}
13. [java]12:41:37,432INFOEnvironment:519usingCGLIBreflectionoptimizer
14. [java]12:41:37,502INFOConfiguration:329Mappingresource:Personnes.hbm.xml
15. [java]12:41:38,784INFOBinder:229Mappingclass:Personnes>personnes
16. [java]12:41:38,984INFOConfiguration:595processingonetomanyassociationmappings
17. [java]12:41:38,994INFOConfiguration:604processingonetooneassociationproperty
18. references
19. [java]12:41:38,994INFOConfiguration:629processingforeignkeyconstraints
20. [java]12:41:39,074INFODialect:82Usingdialect:net.sf.hibernate.dialect.MySQLDialect
21. [java]12:41:39,084INFOSettingsFactory:62Useouterjoinfetching:true
22. [java]12:41:39,104INFODriverManagerConnectionProvider:41UsingHibernate
23. builtinconnectionpool(notforproductionuse!)
24. [java]12:41:39,114INFODriverManagerConnectionProvider:42Hibernateco
25. nnectionpoolsize:20
26. [java]12:41:39,144INFODriverManagerConnectionProvider:71usingdriver
27. :com.mysql.jdbc.DriveratURL:jdbc:mysql://localhost/testDB
28. [java]12:41:39,154INFODriverManagerConnectionProvider:72connectionp
29. roperties:{user=root,password=}
30. [java]12:41:39,185INFOTransactionManagerLookupFactory:33NoTransacti
31. onManagerLookupconfigured(inJTAenvironment,useofprocesslevelreadwrite
32. cacheisnotrecommended)
33. [java]12:41:39,625INFOSettingsFactory:102Usescrollableresultsets:true
34. [java]12:41:39,635INFOSettingsFactory:105UseJDBC3getGeneratedKeys():true
35. [java]12:41:39,635INFOSettingsFactory:108Optimizecacheforminimalputs:false
36. [java]12:41:39,635INFOSettingsFactory:117Querylanguagesubstitutions:{}
37. [java]12:41:39,645INFOSettingsFactory:128cacheprovider:net.sf.ehcache.hibernate.
38. Provider
39. [java]12:41:39,685INFOConfiguration:1080instantiatingandconfiguringcaches
40. [java]12:41:39,946INFOSessionFactoryImpl:119buildingsessionfactory
41. [java]12:41:41,237INFOSessionFactoryObjectFactory:82noJNDInameconfigured
42. [java]12:41:41,768INFOSessionFactoryImpl:531closing
43. [java]12:41:41,768INFODriverManagerConnectionProvider:137cleaningup
44. connectionpool:jdbc:mysql://localhost/testDB
45. BUILDSUCCESSFUL
46. Totaltime:7seconds
47. C:\java\test\testhibernate>

54.6. L'obtention d'une occurrence partir de son identifiant


La mthode load() de la classe Session permet d'obtenir une instance de la classe encapsulant les donnes de l'occurrence de la base dont l'identifiant
est fourni en paramtre.

Il existe deux surcharges de la mthode:

la premire attend en premier paramtre le type de la classe des donnes et renvoie une nouvelle instance de cette classe
la seconde attend en paramtre une instance de la classe des donnes et la met jour avec les donnes retrouves

Exemple :

01. importnet.sf.hibernate.*;
02. importnet.sf.hibernate.cfg.Configuration;
03.
https://www.jmdoudoux.fr/java/dej/chaphibernate.htm 7/105
24/04/2017 DvelopponsenJavaHibernate
03.
04. publicclassTestHibernate2{
05.
06. publicstaticvoidmain(Stringargs[])throwsException{
07. Configurationconfig=newConfiguration();
08. config.addClass(Personnes.class);
09. SessionFactorysessionFactory=config.buildSessionFactory();
10. Sessionsession=sessionFactory.openSession();
11.
12. try{
13. Personnespersonne=(Personnes)session.load(Personnes.class,newInteger(3));
14. System.out.println("nom="+personne.getNomPersonne());
15. }finally{
16. session.close();
17. }
18.
19. sessionFactory.close();
20. }
21. }

Rsultat :

01. C:\java\test\testhibernate>antTestHibernate2
02. Buildfile:build.xml
03.
04. init:
05.
06. compile:
07. [javac]Compiling1sourcefiletoC:\java\test\testhibernate\bin
08.
09. TestHibernate2:
10. [java]nom=nom3
11.
12. BUILDSUCCESSFUL
13. Totaltime:9seconds

54.7. L'obtention de donnes


Hibernate utilise plusieurs moyens pour obtenir des donnes de la base de donnes :

Hibernate Query Language (HQL)


API Criteria : Query By Criteria (QBC) et Query BY Example (QBE)
Requtes SQL natives

54.7.1. Le langage de requte HQL

Pour offrir un langage d'interrogation commun toutes les bases de donnes, Hibernate propose son propre langage nomm HQL (Hibernate Query
Language).

L'intrt de HQL est d'tre indpendant de la base de donnes sous jacente : la requte SQL sera gnre par Hibernate partir du HQL en fonction
de la base de donnes prcise via un dialect.

Hibernate Query Language (HQL) est un langage de requtes orient objets qui permet de reprsenter des requtes SQL : les entits utilises dans les
requtes HQL sont des objets et des proprits. La syntaxe de HQL et ses fonctionnalits de base sont trs similaire SQL.

Il est aussi possible d'utiliser l'API Criteria qui va en interne excuter une requte HQL. Le point d'entre est d'obtenir une instance de type Criteria
en invoquant la mthode createCriteria() de la session Hibernate courante : elle attend en paramtre la classe des objets attendus en rsultat. L'API
permet de prciser les diffrents critres qui seront utiliss pour gnrer la requte. L'API Criteria utilise HQL en sous-jacent.

Hibernate propose aussi un support pour excuter des requtes natives. Ceci permet d'utiliser des fonctionnalits de la base de donnes sous-jacente
qui ne soient pas supportes par HQL. Cependant dans ce cas, le support multi-base de donnes offert par HQL sera probablement compromis.

Le langage HQL est proche de SQL avec une utilisation sous forme d'objets des noms de certaines entits: il n'y a aucune rfrence aux tables ou aux
champs car ceux-ci sont rfrencs respectivement par leur classe et leurs proprits. C'est Hibernate qui se charge de gnrer la requte SQL
partir de la requte HQL en tenant compte du contexte (type de base de donnes utilise dfini dans le fichier de configuration et la configuration du
mapping).

54.7.1.1. La syntaxe de HQL

https://www.jmdoudoux.fr/java/dej/chaphibernate.htm 8/105
24/04/2017 DvelopponsenJavaHibernate
HQL possde une syntaxe similaire de celle de SQL : la diffrence majeure est que HQL utilise des objets et leurs proprits alors que SQL utilise des
tables et leurs colonnes

Exception faite des noms de classes et de variables, les requtes HQL ne sont pas sensibles la casse. Gnralement les mots cl HQL sont en
minuscule pour faciliter leur lecture.

Une requte HQL peut tre compose :

de clauses
de fonctions d'agrgation
de sous requtes

Les clauses sont les mots cls HQL qui sont utiliss pour dfinir la requte:

Clause Description Syntaxe Exemple

prcise la classe d'objets dont les occurrences doivent tre


from object [as from Personne as pers (retourne toutes les
from retrouves. Il est possible de dfinir un alias pour un objet en
objectalias] occurrences de type Personne)
utilisant le mot cl alias

prcise les proprits renvoyer. Doit tre utilis avec une clause select pers.nom from Personne as pers (retourne
select
from le nom de toutes les personnes)

from Personne as pers where pers.nom =


prcise une condition qui permet de filtrer les occurrences
where where condition "Dupond" (retourne toutes les personnes dont le
retournes. Doit tre utilis avec une clause select et/ou from
nom est Dupond.

order by propriete
order prcise un ordre de tri sur une ou plusieurs proprits. L'ordre par select pers.nom, pers.prenom from Personne as
[asc|desc] [,
by dfaut est ascendant pers order by pers.nom asc, pers.prenom desc
propriete] ...

group prcise un critre de regroupement pour les rsultats retourns. group by propriete

by Doit tre utilis avec une clause select et/ou from [, propriete] ...

Les fonctions d'agrgation HQL ont un rle similaire celles de SQL : elles permettent de calculer des valeurs agrgeant des valeurs de proprits
issues du rsultat de la requte.

Fonction Syntaxe

count count( [distinct|all|*] object | object.property )

sum sum( [distinct|all] object.property )

avg avg( [distinct|all] object.property )

max max( [distinct|all] object.property )

min min( [distinct|all] object.property )

Rsultat :

1. selectavg(emp.salaire)fromEmployeasemp

Les sous requtes sont des requtes imbriques dans une autre requte

L'utilisation de sous requtes dans HQL est conditionn par le support des sous requtes par la base de donnes sous-jacente. Les sous requtes sont
entoures par des parenthses : elles sont excutes avant la requte principale puisque celle-ci a besoin des rsultats pour son excution.

Rsultat :

1. fromEmployeasempwhereemp.salaire>=(selectavg(Employe.salaire)
2.
3. fromEmploye)

54.7.1.2. La mise en oeuvre de HQL

La mise en oeuvre de HQL peut se faire de plusieurs manires.

Le plus courant est d'obtenir une instance de la classe Query en invoquant la mthode createQuery() de la session Hibernate courante : elle attend en
paramtre la requte HQL qui devra tre excute.

Exemple :

1. Sessionsession;
2. Queryquery=session.createQuery("selectpers.nomfromPersonneaspers");
https://www.jmdoudoux.fr/java/dej/chaphibernate.htm 9/105
24/04/2017 DvelopponsenJavaHibernate
2. Queryquery=session.createQuery("selectpers.nomfromPersonneaspers");
3. Listresult=query.list();

La mthode list() de la classe Query permet d'obtenir une collection qui contient les rsultats de l'excution de la requte.

Il est galement possible de dfinir des requtes utilisant des paramtres nomms grce un objet implmentant l'interface Query. Dans ces requtes,
les paramtres sont prciss avec un caractre : suivi d'un nom unique.

L'interface Query propose de nombreuses mthodes setXXX() pour associer chaque paramtre une valeur en fonction du type de la valeur (XXX
reprsente le type). Chacune de ces mthodes possde deux surchargespermettant de prciser le paramtre ( partir de son nom ou de son index dans
la requte) et sa valeur.

Pour parcourir la collection des occurrences trouves, l'interface Query propose la mthode list() qui renvoie une collection de type List ou la mthode
iterate() qui renvoie un itrateur sur la collection.

Exemple :

01. importnet.sf.hibernate.*;
02. importnet.sf.hibernate.cfg.Configuration;
03. importjava.util.*;
04.
05. publicclassTestHibernate8{
06.
07. publicstaticvoidmain(Stringargs[])throwsException{
08. SessionFactorysessionFactory=newConfiguration().configure().buildSessionFactory();
09. Sessionsession=sessionFactory.openSession();
10.
11. try{
12. Queryquery=session.createQuery("fromPersonnespwherep.nomPersonne=:nom");
13. query.setString("nom","nom2");
14. Iteratorpersonnes=query.iterate();
15.
16. while(personnes.hasNext()){
17. Personnespersonne=(Personnes)personnes.next();
18. System.out.println("nom="+personne.getNomPersonne());
19. }
20. }finally{
21. session.close();
22. }
23.
24. sessionFactory.close();
25. }
26. }

Rsultat :

01. C:\java\test\testhibernate>antTestHibernate8
02. Buildfile:build.xml
03.
04. init:
05. [copy]Copying1filetoC:\java\test\testhibernate\bin
06.
07. compile:
08.
09. TestHibernate8:
10. [java]nom=nom2
11.
12. BUILDSUCCESSFUL
13. Totaltime:7seconds

La mthode find() de la classe Session permet d'effectuer une recherche d'occurrences grce la requte fournie en paramtre.

Exemple : rechercher toutes les occurrences d'une table

01. importnet.sf.hibernate.*;
02. importnet.sf.hibernate.cfg.Configuration;
03. importjava.util.*;
04.
05. publicclassTestHibernate3{
06.
07. publicstaticvoidmain(Stringargs[])throwsException{
08. Configurationconfig=newConfiguration();
09. config.addClass(Personnes.class);
10. SessionFactorysessionFactory=config.buildSessionFactory();
11. Sessionsession=sessionFactory.openSession();
12.
13. try{
14. Listpersonnes=session.find("fromPersonnes");
15. for(inti=0;i<personnes.size();i++){
16. Personnespersonne=(Personnes)personnes.get(i);
17. System.out.println("nom="+personne.getNomPersonne());
18. }
19. }finally{
20. session.close();
21. }
https://www.jmdoudoux.fr/java/dej/chaphibernate.htm 10/105
24/04/2017 DvelopponsenJavaHibernate
21. }
22. sessionFactory.close();
23. }
24. }

Rsultat :

01. C:\java\test\testhibernate>antTestHibernate3
02. Buildfile:build.xml
03.
04. init:
05.
06. compile:
07. [javac]Compiling1sourcefiletoC:\java\test\testhibernate\bin
08.
09. TestHibernate3:
10. [java]nom=nom1
11. [java]nom=nom2
12. [java]nom=nom3
13.
14. BUILDSUCCESSFUL
15. Totaltime:14seconds

La mthode find() possde deux surcharges pour permettre de fournir un seul ou plusieurs paramtres dans la requte.

La premire surcharge permet de fournir un seul paramtre: elle attend en paramtre la requte, la valeur du paramtre et le type du paramtre.

Exemple :

01. importnet.sf.hibernate.*;
02. importnet.sf.hibernate.cfg.Configuration;
03. importjava.util.*;
04.
05. publicclassTestHibernate4{
06.
07. publicstaticvoidmain(Stringargs[])throwsException{
08. Configurationconfig=newConfiguration();
09. config.addClass(Personnes.class);
10. SessionFactorysessionFactory=config.buildSessionFactory();
11. Sessionsession=sessionFactory.openSession();
12.
13. try{
14. Listpersonnes=session.find("fromPersonnespwherep.nomPersonne=?",
15. "nom1",Hibernate.STRING);
16. for(inti=0;i<personnes.size();i++){
17. Personnespersonne=(Personnes)personnes.get(i);
18. System.out.println("nom="+personne.getNomPersonne());
19. }
20. }finally{
21. session.close();
22. }
23.
24. sessionFactory.close();
25. }
26. }

Rsultat :

01. C:\java\test\testhibernate>antTestHibernate4
02. Buildfile:build.xml
03.
04. init:
05.
06. compile:
07. [javac]Compiling1sourcefiletoC:\java\test\testhibernate\bin
08.
09. TestHibernate4:
10. [java]nom=nom1
11.
12. BUILDSUCCESSFUL

Dans la requte du prcdent exemple, un alias nomm p est dfini pour la classe Personnes. Le mode de fonctionnement d'un alias est similaire en
HQL et en SQL.

La classe Session propose une mthode iterate() dont le mode de fonctionnement est similaire la mthode find() mais elle renvoie un itrateur (objet
de type Iterator) sur la collection des lments retrouvs plutt que la collection elle mme.

Exemple :

01. importnet.sf.hibernate.*;
02. importnet.sf.hibernate.cfg.Configuration;
03. importjava.util.*;
https://www.jmdoudoux.fr/java/dej/chaphibernate.htm 11/105
24/04/2017 DvelopponsenJavaHibernate
03. importjava.util.*;
04.
05. publicclassTestHibernate6{
06.
07. publicstaticvoidmain(Stringargs[])throwsException{
08. Configurationconfig=newConfiguration();
09. config.addClass(Personnes.class);
10. SessionFactorysessionFactory=config.buildSessionFactory();
11. Sessionsession=sessionFactory.openSession();
12.
13. try{
14. Iteratorpersonnes=session.iterate("fromPersonnes");
15. while(personnes.hasNext()){
16. Personnespersonne=(Personnes)personnes.next();
17. System.out.println("nom="+personne.getNomPersonne());
18. }
19. }finally{
20. session.close();
21. }
22.
23. sessionFactory.close();
24. }
25. }

Rsultat :

01. C:\java\test\testhibernate>antTestHibernate6
02. Buildfile:build.xml
03.
04. init:
05.
06. compile:
07. [javac]Compiling1sourcefiletoC:\java\test\testhibernate\bin
08.
09. TestHibernate6:
10. [java]nom=nom1
11. [java]nom=nom2
12. [java]nom=nom3
13.
14. BUILDSUCCESSFUL

Il est aussi possible d'utiliser la clause order by dans une requte HQL pour dfinir l'ordre de tri des occurrences.

Exemple:

List personnes = session.find("from Personnes p order by p.nomPersonne desc")

Il est possible d'utiliser des fonctions telles que count() pour compter le nombre d'occurrences.

Exemple :

01. importnet.sf.hibernate.*;
02. importnet.sf.hibernate.cfg.Configuration;
03. importjava.util.*;
04.
05. publicclassTestHibernate5{
06.
07. publicstaticvoidmain(Stringargs[])throwsException{
08. Configurationconfig=newConfiguration();
09. config.addClass(Personnes.class);
10. SessionFactorysessionFactory=config.buildSessionFactory();
11. Sessionsession=sessionFactory.openSession();
12.
13. try{
14. intcompteur=((Integer)session.iterate(
15. "selectcount(*)fromPersonnes").next()).intValue();
16. System.out.println("compteur="+compteur);
17. }finally{
18. session.close();
19. }
20.
21. sessionFactory.close();
22. }
23. }

Rsultat :

01. C:\java\test\testhibernate>antTestHibernate5
02. Buildfile:build.xml
03.
04. init:
05.
06. compile:
07. [javac]Compiling1sourcefiletoC:\java\test\testhibernate\bin
08.
09. TestHibernate5:
10. [java]compteur=3
https://www.jmdoudoux.fr/java/dej/chaphibernate.htm 12/105
24/04/2017 DvelopponsenJavaHibernate
10. [java]compteur=3
11.
12. BUILDSUCCESSFUL

Hibernate propose galement d'externaliser une requte dans le fichier de mapping.

54.7.2. L'API Criteria

En plus du langage HQL pour raliser des requtes d'extraction de donnes, Hibernate propose une API qui permet de construire des requtes pour
interroger la base de donnes. L'API Criteria d'Hibernate propose donc une alternative HQL sous la forme d'une API.

Le HQL possde une syntaxe drive de celle de SQL dans laquelle les notions relationnelles sont remplaces par des notions objets. Ceci oblige les
dveloppeurs utiliser une syntaxe proche de celle du SQL.

L'API Criteria Query propose des objets pour dfinir les critres d'une requte ce qui permet aux dveloppeurs de les dfinir d'une manire oriente
objet plutt que d'utiliser le HQL.

L'API Criteria propose donc d'avoir une approche oriente objet pour dfinir des requtes et obtenir des donnes. L'utilisation de cette API permet
d'avoir un meilleur contrle grce la compilation.

Cette API permet de facilement combiner de nombreux critres optionnels pour crer une requte : elle est particulirement adapte pour crer
dynamiquement des requtes la vole comme c'est le cas par exemple pour des requtes effectuant des recherches multicritres partir
d'informations fournies par l'utilisateur.

Elle offre pour la plupart des fonctionnalits une approche bi directionnelle :

appliquer un critre en dsignant la proprit sur laquelle il s'applique


appliquer un critre sur une proprit

Elle propose des classes et des interfaces qui encapsulent les fonctionnalits de SQL dont les principales sont :

Criteria
Criterion
Restrictions
Projection
Order

L'interface org.hibernate.criterion.Criteria est le point d'entre pour utiliser l'API Criteria. Elle permet de dfinir une requte partir de critres
pour retrouver des donnes.

Exemple :

1. select*fromPersonne

Voici le code quivalent avec l'API Criteria :

Exemple :

1. Listpersonnes=session.createCriteria(Personne.class).list();

Les critres de recherche permettant de restreindre les donnes retournes par la requte sont dfinis par l'interface
org.hibernate.criterion.Criterion. Le type Criterion encapsule un lment de la clause "where" de la requte SQL qui sera gnre.

Exemple :

01. Criteriacriteria=session.createCriteria(Personne.class);
02. Criterioncritere=Restrictions.eq("id",2l);
03. criteria.add(critere);
04. Listpersonnes=criteria.list();
05.
06. System.out.println("nbpersonnes="+personnes.size());
07. Iteratorit=personnes.iterator();
08. while(it.hasNext()){
09. Personnepersonne=(Personne)it.next();
10. System.out.println("Personne:"+personne);
11. }

La classe org.hibernate.criterion.Restrictions est une fabrique qui propose des mthodes statiques pour crer des instances de type Criterion

Depuis la version 3.x d'Hibernate, il est prfrable d'utiliser la classe Restrictions sa classe fille Expressions.

https://www.jmdoudoux.fr/java/dej/chaphibernate.htm 13/105
24/04/2017 DvelopponsenJavaHibernate
L'interface org.hibernate.criterion.Projection encapsule un champ en rponse de la requte (un champ dans la clause "select" de la requte SQL).

La classe org.hibernate.criterion.Projections est une fabrique pour les instances de type Projection.

Exemple :

1. SELECTnom
2. FROMPersonne

Exemple :

01. List
02. noms=session.createCriteria(Personne.class)
03. .setProjection(Projections.property("nom"))
04. .list();
05.
06. System.out.println("nbpersonnes="+noms.size());
07.
08. Iteratorit=noms.iterator();
09. while(it.hasNext()){
10. Stringnom=(String)it.next();
11. System.out.println("Personne:"+nom);
12. }

La classe Order encapsule une clause SQL "order by".

54.7.2.1. L'utilit de HQL et de l'API Criteria

L'API Criteria permet de dfinir la vole des recherches de donnes multicritres complexes. Un exemple typique d'utilisation o cette API est
particulirement utile est la recherche de donnes multicritres o elle va permettre de facilement construire dynamiquement les critres appliquer
en fonction de ceux prciss par l'utilisateur de l'application.

Ceci est d'autant plus vrai que le nombre de critres optionnels est important : la gnration dynamique peut alors devenir particulirement complexe
surtout si elle implique des jointures conditionnes par les critres prciss.

L'approche traditionnelle consiste construire dynamiquement la requte HQL par concatnation des chanes de caractres qui correspondent chaque
critre renseign avec gnralement plusieurs problmatiques grer :

la gestion des oprateurs logiques notamment pour l'omettre dans le cas du premier critre
la gestion des jointures utiliser (ajout des classes et des critres de jointures)
l'utilisation directe des donnes dans la requte gnre (pouvant par exemple conduire des failles de scurit dans les applications web)

Exemple :

01. publicListrechercher(Sessionsession,
02. Stringnom,
03. Stringprenom,
04. DatedateDeb,
05. DatedateFin,
06. Integertaille){
07. Map<String,Object>parametres=newHashMap<String,Object>();
08. booleanpremiereClause=true;
09. StringBufferrequeteBuffer=newStringBuffer("fromPersonnep");
10.
11. if(nom!=null){
12. requeteBuffer.append(premiereClause?"where":"and");
13. requeteBuffer.append("p.nom=:nom");
14. parametres.put("nom",nom);
15. premiereClause=false;
16. }
17. if(prenom!=null){
18. requeteBuffer.append(premiereClause?"where":"and");
19. requeteBuffer.append("p.prenom=:prenom");
20. parametres.put("prenom",prenom);
21. premiereClause=false;
22. }
23. if(dateDeb!=null){
24. requeteBuffer.append(premiereClause?"where":"and");
25. requeteBuffer.append("p.dateNais>=:dateDeb");
26. parametres.put("dateDeb",dateDeb);
27. premiereClause=false;
28. }
29. if(dateFin!=null){
30. requeteBuffer.append(premiereClause?"where":"and");
31. requeteBuffer.append("p.dateNais<=:dateFin");
32. parametres.put("endDate",dateFin);
33. premiereClause=false;
34. }
35. if(taille!=null){
36. requeteBuffer.append(premiereClause?"where":"and");
37. requeteBuffer.append("p.taille=:taille");
https://www.jmdoudoux.fr/java/dej/chaphibernate.htm 14/105
24/04/2017 DvelopponsenJavaHibernate
37. requeteBuffer.append("p.taille=:taille");
38. parametres.put("taille",taille);
39. premiereClause=false;
40. }
41.
42. StringrequeteHql=requeteBuffer.toString();
43.
44. Queryquery=session.createQuery(requeteHql);
45.
46. Iterator<String>iter=parametres.keySet().iterator();
47. while(iter.hasNext()){
48. Stringname=iter.next();
49. Objectvalue=parametres.get(name);
50. query.setParameter(name,value);
51. }
52.
53. returnquery.list();
54. }

Cette approche est lourde et source d'erreurs car le code contient des portions similaires rptes. Il est aussi trs important de ne pas concatner
directement des valeurs saisies par l'utilisateur dans la requte.

L'API Criteria propose une solution plus propre, plus concise et plus sre.

Exemple :

01. publicListrechercher(Sessionsession,
02. Stringnom,
03. Stringprenom,
04. DatedateDeb,
05. DatedateFin,
06. Integertaille){
07. Criteriacriteria=session.createCriteria(Personne.class);
08. if(dateDeb!=null){
09. criteria.add(Restrictions.ge("dateNais",dateDeb));
10. }
11. if(dateFin!=null){
12. criteria.add(Restrictions.le("dateNais",dateFin));
13. }
14. if(nom!=null){
15. criteria.add(Restrictions.eq("nom",nom));
16. }
17. if(prenom!=null){
18. criteria.add(Restrictions.eq("prenom",prenom));
19. }
20. if(taille!=null){
21. criteria.add(Restrictions.eq("taille",taille));
22. }
23. Listresultat=criteria.list();
24.
25. returnresultat;
26.
27. }

La quantit de code ncessaire en utilisant l'API Criteria est beaucoup moins importante que la quantit ncessaire la construction dynamique de la
requte HQL.

54.7.2.2. L'interface Criteria

L'interface org.hibernate.Criteria propose des fonctionnalits pour encapsuler une requte compose de critres.

Une instance de l'interface Criteria est obtenue en invoquant la mthode createCriteria() de la session hibernate. Elle attends en paramtre la classe
d'une entit sur laquelle les critres vont s'appliquer.

L'interface Criteria propose diffrentes mthodes pour construire les critres d'interrogation sur une classe persistante.

Mthode Rle

Criteria add(Criterion criterion) ajouter un critre Criteria

addOrder(Order order) ajouter un ordre de tri

Criteria createAlias(String associationPath, String


ajouter une jointure en lui assignant un alias
alias)

Criteria createAlias(String associationPath, String crer un objet de type Criteria pour une entit donne en prcisant son type et en lui assignant
alias, int joinType) un alias

Criteria createCriteria(String associationPath) crer un objet de type Criteria pour une entit donne

Criteria createCriteria(String associationPath, int crer un objet de type Criteria pour une entit donne en prcisant son type de jointure

https://www.jmdoudoux.fr/java/dej/chaphibernate.htm 15/105
24/04/2017 DvelopponsenJavaHibernate
joinType)

Criteria createCriteria(String associationPath,


crer un objet de type Criteria pour une entit donne en lui assignant un alias
String alias)

Criteria createCriteria(String associationPath, crer un objet de type Criteria pour une entit donne en prcisant son type, en lui assignant un
String alias, int joinType) alias et en prcisant son type de jointure

String getAlias() obtenir l'alias de l'entit encapsule dans le Criteria

List list() obtenir les rsultats de la requte

ScrollableResults scroll() obtenir les rsultats comme une instance de type ScrollableResults

obtenir les rsultats comme une instance de type ScrollableResults en prcisant le mode de
ScrollableResults scroll(ScrollMode scrollMode)
parcours

Criteria setCacheable(boolean cacheable) activer ou non la mise en cache des rsultats de la requte

Criteria setCacheMode(CacheMode cacheMode) modifier le mode de mise en cache des rsultats de la requte

Criteria setCacheRegion(String cacheRegion) prciser le nom de la rgion du cache utiliser pour stocker les rsultats de la requte

Criteria setComment(String comment) ajouter un commentaire la requte SQL

Criteria setFetchMode(String associationPath,


prciser le mode de rcupration des donnes dans le cas d'une association entre deux entits
FetchMode mode)

Criteria setFetchSize(int fetchSize) prciser le nombre d'occurrences retournes par la requte

Criteria setFirstResult(int firstResult) prciser la premire occurrence qui sera retourne

Criteria setFlushMode(FlushMode flushMode) prciser le mode de flush de la requte

Criteria setLockMode(LockMode lockMode) prciser le mode de verrou de l'entit

Criteria setLockMode(String alias, LockMode


prciser le mode de verrou pour l'entit dont l'alias est fourni en paramtre
lockMode)

Criteria setMaxResults(int maxResults) assigner un nombre maximum d'occurrences retournes dans le rsultat

Criteria setProjection(Projection projection) prciser le contenu du rsultat de la requte

Criteria setResultTransformer(ResultTransformer
prciser une stratgie de traitement des rsultats de la requte
resultTransformer)

Criteria setTimeout(int timeout) assigner un timeout la requte

ne renvoyer qu'une seule instance en rsultat de la requte ou null si la requte ne renvoie aucun
Object uniqueResult()
rsultat.

Exemple :

1. Criteriacriteria=session.createCriteria(Personne.class);
2. criteria.setMaxResults(10);
3. Listpersonnes=criteria.list();

54.7.2.3. L'interface Criterion

L'interface org.hibernate.criterion.Criterion dfinit les mthodes qui vont permettre de dfinir un critre appliquer dans la requte.

Chaque instance d'un critre doit tre ajoute aux critres de la requte en utilisant la mthodes add() de l'instance de type Criteria.

L'API propose plusieurs fabriques qui permettent d'instancier les diffrents objets qui vont dfinir le contenu de la requte.

Exemple :

1. Listpersonnes=session.createCriteria(Personne.class)
2. .add(Restrictions.like("nom","Dup%"))
3. .add(Restrictions.gt("taille",newInteger(180)))
4. .addOrder(Order.asc("age"))
5. .list();

La classe org.hibernate.criterion.Restrictions est une fabrique qui propose des mthodes pour obtenir diffrentes instances de Criterion.

Exemple :

01. Calendarcal=Calendar.getInstance();
02. cal.set(1980,Calendar.JANUARY,01);
03. DatedateDeb=cal.getTime();
https://www.jmdoudoux.fr/java/dej/chaphibernate.htm 16/105
24/04/2017 DvelopponsenJavaHibernate
03. DatedateDeb=cal.getTime();
04. cal.set(1980,Calendar.DECEMBER,31);
05. DatedateFin=cal.getTime();
06. personnes=session.createCriteria(Personne.class)
07. .add(Restrictions.ge("dateNais",dateDeb))
08. .add(Restrictions.le("dateNais",dateFin))
09. .addOrder(Order.asc("dateNais"))
10. .setFirstResult(0)
11. .setMaxResults(10)
12. .list();

L'interface Criterion possde de nombreuses interfaces filles : AbstractEmptinessExpression, BetweenExpression, Conjunction, Disjunction,
EmptyExpression, Example, ExistsSubqueryExpression, IdentifierEqExpression, IlikeExpression, InExpression, Junction, LikeExpression,
LogicalExpression, NaturalIdentifier, NotEmptyExpression, NotExpression, NotNullExpression, NullExpression, PropertyExpression,
PropertySubqueryExpression, SimpleExpression, SimpleSubqueryExpression, SizeExpression, SQLCriterion, SubqueryExpression.

54.7.2.4. Les restrictions et les expressions

La classe org.hibernate.criterion.Restrictions permet de crer des critres qui sont des conditions permettant de slectionner les donnes retrouver.

La classe Restrictions est une fabrique qui permet de crer des critres de recherche sous la forme d'instances de type Criterion. Les critres
proposs encapsulent les oprateurs SQL standards.

Elle propose des mthodes statiques pour crer des instances des diffrentes implmentations de l'interface Criterion proposes par Hibernate. Ces
critres sont utiliss pour dfinir les occurrences qui seront retournes par le rsultat de la requte.

Exemple :

1. SELECT*FROMPersonneWHEREIdPers=1;

Exemple :

1. Listpersonnes=session.createCriteria(Personne.class)
2. .add(Restrictions.eq("id",1l))
3. .list();

Les conditions standards de SQL sont encapsules dans des objets de type Criterion : pour obtenir une de leurs instances, il faut utiliser les mthodes
statiques de la classe Restrictions dont les principales sont :

Mthode Rle

Mthode utilitaire qui permet de facilement vrifier que plusieurs proprits ont une valeur particulire. Les cls
Criterion allEq(Map properties)
du paramtre de type Map correspondent aux noms des proprits concernes

LogicalExpression and(Criterion
Crer un critre de type "and" qui est vrai si les deux critres sont valus vrai
lhs, Criterion rhs)

Criterion between(String
Permet d'appliquer une contrainte SQL de type "between" : la valeur de la proprit dont le nom est fourni en
propertyName, Object lo, Object
paramtre doit tre comprise entre les deux valeurs fournies
hi)

Crer un objet de type Conjunction qui permet d'utiliser un critre de type and simplement en invoquant sa
Conjunction conjunction() mthode add() pour chaque critre prendre en compte. Le critre encapsul dans l'objet de type Conjunction
sera true si tous les critres qu'il contient sont true

Crer un objet de type Disjunction qui permet d'utiliser un critre de type or simplement en invoquant sa mthode
Disjunction disjunction() add() pour chaque critre prendre en compte. Le critre encapsul dans l'objet de type Disjunction sera true si
au moins un des critres qu'il contient est true

SimpleExpression eq(String Permet d'appliquer une contrainte SQL de type galit : la valeur de la proprit doit tre gale la valeur fournie
propertyName, Object value) en paramtre

PropertyExpression
eqProperty(String propertyl, La valeur des deux proprits doit tre gale
String property2)

SimpleExpression ge(String Permet d'appliquer une contrainte SQL de type "suprieur ou gal" : la valeur de la proprit doit tre suprieure
propertyName, Object value) ou gale la valeur fournie en paramtre

PropertyExpression
geProperty(String propertyl, La valeur de la proprit doit tre suprieure ou gale la valeur de la seconde proprit fournie en paramtre
String property2)

SimpleExpression gt(String Permet d'appliquer une contrainte SQL de type "suprieur " : la valeur de la proprit doit tre suprieure la
propertyName, Object value) valeur fournie en paramtre
https://www.jmdoudoux.fr/java/dej/chaphibernate.htm 17/105
24/04/2017 DvelopponsenJavaHibernate

PropertyExpression
gtProperty(String propertyl, La valeur de la proprit doit tre suprieure la valeur de la seconde proprit fournie en paramtre
String property2)

permet d'appliquer une contrainte SQL de type galit sur l'identifiant : la valeur de la proprit qui est
Criterion idEq(Object value)
l'identifiant doit tre gale celle fournie

Criterion ilike(String property,


Joue le mme rle que la mthode like() mais en tant insensible la casse
Object value)

Joue le mme rle que la mthode like() mais en tant insensible la casse et sans utiliser la syntaxe de
Criterion ilike(String property,
l'oprateur like. MatchMode est une numration qui peut prendre les valeurs START, END, ANYWHERE, ou
String value, MatchMode mode)
EXACT.

Criterion in(String property, La valeur de la proprit dont le nom est fourni en paramtre doit tre gale l'une de celles fournies dans la
Collection values) collection

Criterion in(String Permet d'appliquer une contrainte SQL de type "in" : la valeur de la proprit dont le nom est fourni en paramtre
propertyName, Collection values) doit tre gale l'une de celles fournies dans le tableau

Criterion isEmpty(String
Le contenu de la collection de la proprit dont le nom est fourni en paramtre ne doit pas avoir d'lments
property)

Criterion isNotEmpty(String
Le contenu de la collection de la proprit dont le nom est fourni en paramtre doit avoir au moins un lment
property)

Criterion isNotNull(String Permet d'appliquer une contrainte SQL de type "is not null" : la valeur de la proprit dont le nom est fourni en
propertyName) paramtre doit tre non null

Criterion isNull(String Permet d'appliquer une contrainte SQL de type "is null" : la valeur de la proprit dont le nom est fourni en
propertyName) paramtre doit tre null

SimpleExpression le(String
La valeur de la proprit dont le nom est fourni en paramtre doit tre infrieure ou gale la valeur fournie
property, Object value)

PropertyExpression
leProperty(String propertyl, La valeur de la proprit fournie en paramtre doit tre infrieure ou gale la valeur fournie
String property2)

SimpleExpression like(String La valeur de la proprit dont le nom est fourni en paramtre doit respecter le motif de l'oprateur sql like fourni
property, Object value) en paramtre

SimpleExpression like(String La valeur de la proprit dont le nom est fourni en paramtre doit respecter le motif de l'oprateur sql like
property, String value, dtermin partir des paramtre valeur et mode. MatchMode est une numration qui peut prendre les valeurs
MatchMode mode) START, END, ANYWHERE, ou EXACT.

SimpleExpression lt(String
La valeur de la proprit doit tre infrieure la valeur fournie en paramtre
property, Object value)

PropertyExpression
ltProperty(String propertyl, La valeur de la premire proprit doit tre infrieure la seconde
String property2)

SimpleExpression ne(String Permet d'appliquer une contrainte SQL de type "est diffrent de" : la valeur de la proprit dont le nom est
propertyName, Object value) fourni en paramtre doit tre diffrente de la valeur fournie

PropertyExpression
neProperty(String
La valeur des deux proprits fournies en paramtres doit tre diffrente
propertyName, String
otherPropertyName)

Criterion not(Criterion
L'valuation du critre fourni en paramtre doit tre false
expression)

LogicalExpression or(Criterion
L'valuation d'un des deux critres fourni en paramtre doit tre true
lhs, Criterion rhs)

Criterion sqlRestriction(String
Appliquer une restriction en sql natif
sql)

Criterion sqlRestriction(String
sql, Object[] values, Type[] Appliquer une restriction en sql natif qui va utiliser les paramtres fournis
types)

Criterion sqlRestriction(String
Appliquer une restriction en sql natif qui va utiliser le paramtre fourni
sql, Object value, Type type)

Certaines de ces mthodes attendent un paramtre de type Criterion qui permet de faire des combinaisons de critres.

Les oprateurs de comparaison sont encapuls dans des mthodes de la classe Restrictions : eq(), lt(), le(), gt(), ge().

Exemple :

1. Listpersonnes=session.createCriteria(Personne.class)
2. .add(Restrictions.lt("dateNais",dateSaisie))
3. .list();
https://www.jmdoudoux.fr/java/dej/chaphibernate.htm 18/105
24/04/2017 DvelopponsenJavaHibernate
3. .list();

La classe Restrictions propose aussi des mthodes pour les oprateurs SQL : like, between, in, is null, is not null ...

Exemple :

1. Listpersonnes=session.createCriteria(Personne.class)
2. .add(Restrictions.between("dateNais",dateDeb,dateFin))
3. .add(Restrictions.like("nom","Dup%"))
4. .list();

La classe Restrictions propose aussi des mthodes qui permettent de faire des comparaisons entre proprits.

Exemple :

1. Listpersonnes=session.createCriteria(Personne.class)
2. .add(Restrictions.eqProperty("nom","prenom"))
3. .list();

L'utilisation de la mthode sqlRestriction() peut tre trs pratique mais elle peut nuire la portabilit entre bases de donnes.

Pour prciser l'alias de la table courante dans la portion de requte SQL fournie en paramtre de la mthode sqlRestriction(), il faut utiliser la syntaxe
"{alias}".

Il est possible d'utiliser les mthodes or() et and() pour raliser des combinaisons de critres.

Exemple :

1. Listpersonnes=session.createCriteria(Personne.class)
2. .add(Restrictions.or(Restrictions.eq("prenom","Jean"),
3. Restrictions.eq("prenom","Paul")))
4. .list();

Remarque : il est prfrable d'utiliser la classe Restrictions plutt que sa classe fille Expressions qui est deprecated.

54.7.2.5. Les projections et les aggregations

La classe org.hibernate.criterion.Projection permet de prciser un champ qui sera retourn dans le rsultat de la requte : ce champ peut tre issu
d'une table, du calcul d'une aggrgation, de la dfinition d'un alias, ...

Pour ajouter un champ, il faut passer le nom du champ en paramtre de la mthode statique property() de la classe Projection. L'instance retourne est
passe en paramtre de la mthode setProjection().

La classe org.hibernate.criterion.Projections est une fabrique pour crer des instances de type Projection.

Pour prciser plusieurs champs, il faut utiliser la mthode propertyList() de la classe ProjectionList.

Exemple :

1. SELECTNOM,PRENOMFROMPERSONNE

Exemple :

01. Listresultats=session.createCriteria(Personne.class)
02. .setProjection(Projections.projectionList()
03. .add(Projections.property("nom"))
04. .add(Projections.property("prenom")))
05. .list();
06.
07. System.out.println("nbpersonnes="+resultats.size());
08. Iteratorit=resultats.iterator();
09. while(it.hasNext()){
10. Object[]donnees=(Object[])it.next();
11. System.out.println("Nom:"+donnees[0]
12. +"Prenom:"+donnees[1]);
13. }

https://www.jmdoudoux.fr/java/dej/chaphibernate.htm 19/105
24/04/2017 DvelopponsenJavaHibernate
Pour appliquer une collection de type Projection aux critres de la requte, il faut utiliser la mthode setProjection() de la classe Criteria. Une
collection d'objets de type Projection est encapsule dans un objet de type ProjectionList. La mthode add() permet d'ajouter une Projection la
collection.

Exemple :

1. Listresultats=session.createCriteria(Personne.class)
2. .setProjection(Projections.rowCount())
3. .list();
4. Longvaleur=(Long)resultats.get(0);
5. System.out.println("nbpersonnes="+valeur);

Les donnes de certaines requtes doivent parfois tre groupes ou intervenir dans un calcul d'aggrgation : il faut pour cela utiliser les fonctionnalits
encapsules dans la classe Projections. Toutes les fonctions d'aggrgation de la classe Projections sont des mthodes statiques.

La classe Projections possde plusieurs mthodes statiques :

Mthode Rle

static Projections alias(Projection projection, String alias) Assigner un alias

static AgregateProjection avg(String property) Calculer la moyenne du champ dont le nom est fourni en paramtre

static CountProjection count(String property) Calculer le nombre d'occurrences du champ dont le nom et fourni en paramtre

Calculer le nombre d'occurrences distinctes du champ dont le nom et fourni en


static CountProjection countDistinct(String property)
paramtre

static Projection distinct(Projection projection) Ne retourner que des valeurs uniques (supprimer les valeurs en doublon).

static PropertyProjection groupProperty(String property) Grouper les rsultats sur la proprit fournie

static IdentifierProjection id() Renvoyer l'identifiant

static AggregateProjection max(String property) Dterminer la plus grande valeur pour le champ dont le nom est fourni en paramtre

static AggregateProjection min(String property) Dterminer la plus petite valeur pour le champ dont le nom est fourni en paramtre

static ProjectionList projectionList() Retourner une collection de projections

static PropertyProjection property(String property) Ajouter la proprit fournie en paramtre

static Projection rowCount() Calculer le nombre d'occurrences retournes par la requte

static Projection sqlGroupProjection(String sql, String Ajouter du code SQL spcifique la base de donnes utilise pour dterminer un
groupBy, String[] columnAliases, Type[] types) groupage. Le paramtre groupBy peut contenir une clause GROUP BY

static Projection sqlProjection(String sql, String[] Ajouter du code SQL spcifique la base de donnes utilise pour dterminer la liste de
columnAliases, Type[] types) champs retourne par la requte

static AggregateProjection sum(String property) Calculer la sommes des valeurs pour le champ dont le nom est fourni en paramtre

Lors de l'utilisation d'oprateurs d'aggrgation, il est frquent de grouper les donnes par rapport un champ particulier. La classe Projections
prossde la mthode groupProperty() qui permet de dfinir une clause "group by" qui sera utilise avec le nom du champ fourni en paramtre.

Exemple :

1. SELECTCOUNT(ID)FROMPERSONNEGROUPBYTAILLE

Exemple :

01. Listresultats=session.createCriteria(Personne.class)
02. .setProjection(Projections.projectionList()
03. .add(Projections.count("id"))
04. .add(Projections.groupProperty("taille")))
05. .list();
06.
07. Iteratorit=resultats.iterator();
08. while(it.hasNext()){
09. Object[]donnees=(Object[])it.next();
10. System.out.println("Nombre:"+donnees[0]+"taille:"+donnees[1]);
11. }

54.7.2.6. La classe Property

https://www.jmdoudoux.fr/java/dej/chaphibernate.htm 20/105
24/04/2017 DvelopponsenJavaHibernate
La classe org.hibernate.criterion.Property est une fabrique qui permet de crer des critres spcifiques appliqus la proprit encapsule. Ceci
permet d'appliquer des critres directement sur une proprit.

La mthode statique forName() de la classe Property permet d'obtenir une instance qui encapsule une proprit.

La classe org.hibernate.criterion.Property propose plusieurs mthodes pour appliquer des critres sur la proprit qu'elle encapsule.

Les principales mthodes sont :

Mthode Rle

Order asc() Trier les valeurs de la proprit dans un ordre ascendant

AggregateProjection avg() Crer un champ qui calcule la moyenne des occurrences de la proprit

Criterion between(Object Crer un critre qui requiert que la valeur de la proprit soit comprise entre les valeurs min et max fournies en
min, Object max) paramtres

CountProjection count() Crer un champ qui compte le nombre d'occurrences de la proprit

Order desc() Trier les valeurs de la proprit dans un ordre descendant

SimpleExpression eq(Object Crer un critre pour filtrer les rsultats de faon ne retourner que les occurrences dont la valeur de la proprit
value) soit gale celle fournie en paramtre

PropertyExpression Crer un critre qui requiert que la valeur de la proprit soit gale celle de la valeur de la proprit fournie en
eqProperty(Property other) paramtre

PropertyExpression Crer un critre qui requiert que la valeur de la proprit soit gale celle de la valeur de la proprit dont le nom est
eqProperty(String property) fourni en paramtre

SimpleExpression ge(Object
Crer un critre qui requiert que la valeur de la proprit soit suprieure ou gale celle fournie en paramtre
value)

PropertyExpression Crer un critre qui requiert que la valeur de la proprit soit suprieure ou gale celle de la valeur de la proprit
geProperty(Property other) fournie en paramtre

PropertyExpression Crer un critre qui requiert que la valeur de la proprit soit suprieure ou gale celle de la valeur de la proprit
geProperty(String property) dont le nom est fourni en paramtre

PropertyProjection group() Demander un groupage sur les valeurs de la proprit

SimpleExpression gt(Object
Crer un critre qui requiert que la valeur de la proprit soit suprieure celle fournie en paramtre
value)

PropertyExpression Crer un critre qui requiert que la valeur de la proprit soit suprieure celle de la valeur de la proprit fournie en
gtProperty(Property other) paramtre

PropertyExpression Crer un critre qui requiert que la valeur de la proprit soit suprieure celle de la valeur de la proprit dont le
gtProperty(String property) nom est fourni en paramtre

Criterion in(Collection
Crer un critre qui requiert que la valeur de la proprit doit tre gale une de celles fournies
values)

in(Object[] values) Crer un critre qui requiert que la valeur de la proprit doit tre gale une de celles fournies

Criterion isEmpty() Crer un critre qui requiert que la valeur de la proprit ne possde aucun lment

Criterion isNotEmpty() Crer un critre qui requiert que la valeur de la proprit possde au moins un lment

Criterion isNotNull() Crer un critre qui requiert que la valeur de la proprit ne soit pas null

Criterion isNull() Crer un critre qui requiert que la valeur de la proprit soit null

SimpleExpression le(Object
Crer un critre qui requiert que la valeur de la proprit soit infrieure ou gale celle fournie en paramtre
value)

PropertyExpression Crer un critre qui requiert que la valeur de la proprit soit infrieure ou gale celle de la valeur de la proprit
leProperty(Property other) fournie en paramtre

PropertyExpression Crer un critre qui requiert que la valeur de la proprit soit infrieure ou gale celle de la valeur de la paramtre
leProperty(String property) dont le nom est fourni en paramtre

SimpleExpressionlike(Object
Crer un critre qui requiert que la valeur de la proprit respecte le motif fourni au sens de l'oprateur SQL like
value)

Crer un critre qui requiert que la valeur de la proprit respecte un motif fourni au sens de l'oprateur SQL like Le
like(String value, motif est construit partir de la sous chane fournie en paramtre et de son mode recherche qui peut prendre les
MatchMode mode) valeurs START, END, ANYWHERE, and EXACT. Ceci permet d'viter d'avoir manipuler la syntaxe de l'oprateur
SQL like.

SimpleExpression lt(Object
Crer un critre qui requiert que la valeur de la proprit soit suprieure ou gale celle fournie en paramtre
value)

PropertyExpression Crer un critre qui requiert que la valeur de la proprit soit suprieure ou gale celle de la valeur de la proprit
ltProperty(Property other) fournie en paramtre

PropertyExpression Crer un critre qui requiert que la valeur de la proprit soit infrieure ou gale celle de la valeur de la paramtre
ltProperty(String property) dont le nom est fourni en paramtre

AggregateProjection max() Crer un champ qui va contenir la valeur la plus leve de la proprit
https://www.jmdoudoux.fr/java/dej/chaphibernate.htm 21/105
24/04/2017 DvelopponsenJavaHibernate
AggregateProjection max()

AggregateProjection min() Crer un champ qui va contenir la valeur la moins leve de la proprit

PropertyProjection
Crer un critre qui requiert que la valeur de la proprit soit diffrente de celle fournie en paramtre
ne(Object value)

PropertyProjection Crer un critre qui requiert que la valeur de la proprit soit diffrente de celle de la valeur de la proprit fournie
neProperty(Property other) en paramtre

PropertyExpression Crer un critre qui requiert que la valeur de la proprit soit diffrente de celle de la valeur de la paramtre dont le
neProperty(String property) nom est fourni en paramtre

54.7.2.7. Le tri des rsultats

Il est possible de demander le tri des rsultats de la requte en utilisant la mthode addOrderO de la classe Criteria et la classe Order.

La classe org.hibernate.criterion.Order permet d'encapsuler une clause de tri dans la requte en prcisant le sens (ascendant ou descendant) sur un
champ.

Elle possde plusieurs mthodes :

Mthode Rle

static Order asc(String) Demander un tri ascendant sur le nom du champ fourni en paramtre de la mthode

static Order desc(String) Demander un tri descendant sur le nom du champ fourni en paramtre de la mthode

Order ignoreCase() Demander d'ignorer la casse lors du tri des donnes

Exemple :

1. Listresultats=session.createCriteria(Personne.class)
2. .add(Restrictions.between("dateNais",dateDeb,dateFin))
3. .addOrder(Order.desc("dateNais"))
4. .addOrder(Order.asc("nom"));

54.7.2.8. La jointure de tables

Il est trs frquent d'avoir effectuer une ou plusieurs jointures sur les tables d'une requte pour obtenir les donnes souhaites.

En SQL, la jointure se fait en utilisant les tables dans la clause from et en indiquant les conditions de la jointure.

Exemple :

1. SELECTP.*,A.*FROMPersonneP,AdresseAWHEREP.adresse_id=A.id
2. ANDA.Nom='Dupond';

En HQL, il est possible de charger les donnes d'objets dpendants en utilisant la clause "left join fetch" :

Exemple :

1. fromPersonnepersonne
2. wherePersonne.nom=:nomleftjoinfetchpersonne.adresse

La mthode setFetchMode() permet de faire une jointure avec l'API Criteria.

Exemple :

01. packagecom.jmdoudoux.test.hibernate;
02.
03. importjava.util.Iterator;
04. importjava.util.List;
05. importorg.hibernate.FetchMode;
06. importorg.hibernate.Session;
07. importorg.hibernate.SessionFactory;
08. importorg.hibernate.Transaction;
09. importorg.hibernate.cfg.AnnotationConfiguration;
10.

11. publicclassTestHibernateCriteria{
https://www.jmdoudoux.fr/java/dej/chaphibernate.htm 22/105
24/04/2017 DvelopponsenJavaHibernate
11. publicclassTestHibernateCriteria{
12.
13. publicstaticvoidmain(Stringargs[]){
14. SessionFactorysessionFactory=newAnnotationConfiguration().configure()
15. .buildSessionFactory();
16. Transactiontransaction=null;
17. Listpersonnes=null;
18. Sessionsession=sessionFactory.openSession();
19.
20. try{
21. transaction=session.beginTransaction();
22. personnes=session.createCriteria(Personne.class)
23. .setFetchMode("adresse",FetchMode.JOIN)
24. .list();
25. System.out.println("nbpersonnes="+personnes.size());
26.
27. Iteratorit=personnes.iterator();
28. while(it.hasNext()){
29. Personnepersonne=(Personne)it.next();
30.
31. System.out.println("Personne:"+personne);
32. System.out.println("Adresse:"+personne.getAdresse());
33. }
34.
35. transaction.commit();
36. }catch(Exceptione){
37. transaction.rollback();
38. e.printStackTrace();
39. }finally{
40. session.close();
41. }
42. sessionFactory.close();
43. }
44. }

La mthode setFetchMode() attend deux paramtres :

le nom de la classe de l'entit dont la table sera jointe avec celle de l'entit courante
le mode de rcupration des donnes: DEFAULT (valeur configure dans le mapping), EAGER (deprecated: utiliser JOIN), JOIN (rcupration
des donnes par jointure), LAZY (deprecated: utiliser SELECT), SELECT (rcupration des donnes par une requte ddie)

Parfois, il est ncessaire de joindre les entits mais il est inutile de rcuprer les donnes de l'entit jointe : dans ce cas la jointure n'est utile que pour
dfinir un ou plusieurs critres de la requte

Exemple :

1. fromPersonnepjoinp.adresseawherea.cp='54000'

Il est possible d'utiliser la mthode createCriteria() pour crer une jointure :

Exemple :

01. packagecom.jmdoudoux.test.hibernate;
02.
03. importjava.util.Iterator;
04. importjava.util.List;
05. importorg.hibernate.Session;
06. importorg.hibernate.SessionFactory;
07. importorg.hibernate.Transaction;
08. importorg.hibernate.cfg.AnnotationConfiguration;
09. importorg.hibernate.criterion.Restrictions;
10.
11. publicclassTestHibernateCriteria{
12.
13. publicstaticvoidmain(Stringargs[]){
14. SessionFactorysessionFactory=newAnnotationConfiguration().configure()
15. .buildSessionFactory();
16.
17. Transactiontransaction=null;
18. Listpersonnes=null;
19.
20. Sessionsession=sessionFactory.openSession();
21. try{
22. transaction=session.beginTransaction();
23. personnes=session.createCriteria(Personne.class)
24. .createCriteria("adresse","a")
25. .add(Restrictions.eq("a.cp","54700"))
26. .list();
27.
28. System.out.println("nbpersonnes="+personnes.size());
29.
30. Iteratorit=personnes.iterator();
31. while(it.hasNext()){
32. Personnepersonne=(Personne)it.next();
33. System.out.println("Personne:"+personne);
34. System.out.println("Adresse:"+personne.getAdresse());
35. }

36.
https://www.jmdoudoux.fr/java/dej/chaphibernate.htm 23/105
24/04/2017 DvelopponsenJavaHibernate
36.
37. transaction.commit();
38. }catch(Exceptione){
39. transaction.rollback();
40. e.printStackTrace();
41. }finally{
42. session.close();
43. }
44.
45. sessionFactory.close();
46. }
47. }

Attention: dans ce cas, le premier paramtre de la mthode createCriteria() est le nom d'une proprit et non le nom de classe.

Il est aussi possible d'utiliser la mthode createAlias() qui vite d'avoir crer une nouvelle instance de la classe Criteria.

Exemple :

1. personnes=session.createCriteria(Personne.class)
2. .createAlias("adresse","a")
3. .add(Restrictions.eq("a.cp","54000"))
4. .list();

Les restrictions sont aussi utilisables avec une jointure dans laquelle les donnes de la table jointe sont rcupres.

Exemple :

1. SELECTG.*,P.*FROMPersonnesP,GroupeGWHEREG.IdGroup=P.IdGroupANDG.IdGroup=l;

Exemple :

1. Listgroupes=session.createCriteria(Groupe.class)
2. .setFetchMode("Personne",FetchMode.JOIN)
3. .add(Restrictions.eq("IdGroup","1"))
4. .list();

54.7.2.9. La cration de critres partir de donnes

La classe Example permet de crer des critres par l'exemple : pour cela, il faut instancier une entit et lui affecter les diffrentes valeurs qui seront
utilises comme critres.

La mthode static create() qui attend en paramtre une instance d'une entit va utiliser l'instrospection pour rechercher les proprits qui possdent
une valeur et gnrer une instance de type Example contenant les critres correspondants aux proprits renseignes.

Exemple :

01. transaction=session.beginTransaction();
02. DatedateDebut=newGregorianCalendar(1980,Calendar.JANUARY,01).getTime();
03. DatedateFin=newGregorianCalendar(1981,Calendar.JANUARY,01).getTime();
04.
05. PersonnepersonneExemple=newPersonne();
06. personneExemple.setNom("Dupond");
07. personneExemple.setPrenom("Michel");
08. Exampleexample=Example.create(personneExemple).ignoreCase().excludeZeroes();
09. List<Personne>resultats=session.createCriteria(Personne.class)
10. .add(example)
11. .add(Restrictions.between("dateNais",
12. dateDebut,dateFin)).list();
13. System.out.println("nbpersonnes="+personnes.size());
14.
15. Iteratorit=personnes.iterator();
16. while(it.hasNext()){
17. Personnepersonne=(Personne)it.next();
18. System.out.println("Personne:"+personne);
19. System.out.println("Adresse:"+personne.getAdresse());
20. }
21. transaction.commit();

Il est possible de configurer le comportement de la classe Example en utilisant les diffrentes mthodes qu'elle propose cette fin :

Mthode Rle

https://www.jmdoudoux.fr/java/dej/chaphibernate.htm 24/105
24/04/2017 DvelopponsenJavaHibernate

Example enableLike() Utiliser l'oprateur like pour toutes les proprits de type String

Utiliser l'oprateur like pour toutes les proprits de type String avec la stratgie de
Example enableLike(MatchMode matchMode)
correspondance fournie en paramtre

Example excludeNone() Ne pas exclure les proprits dont la valeur est null ou zro

Example excludeProperty(String name) Ignorer la proprit dont le nom est fourni en paramtre

Example excludeZeroes() Ignorer les proprits dont la valeur est zro

Example ignoreCase() Ignorer la casse des proprits de type String

Example setEscapeCharacter(Character
Prciser le caractre d'chappement utilis dans la clause like
escapeCharacter)

Cette API est particulirement utile si le nombre de proprits est important. Comme la classe Example hrite de la classe Criterion, elle peut tre
utilise pour crer les critres "simple" et utiliser d'autres classes pour les critres plus complexes ou spcifiques.

54.7.2.10. Le choix entre HQL et l'API Criteria

L'API Criteria est trs puissante et elle est particulirement bien adapte pour certaines tches (notamment la cration de requtes dynamiques la
vole impliquant de nombreux critres optionnels comme par exemple dans un formulaire de recherche multicritres).

Dans ces cas, sa mise en oeuvre peut permettre d'avoir un code plus propre, plus sre et plus maintenable.

Cependant, son utilisation ne peut pas toujours tre gnralise tous les cas de figure car l'utilisation de HQL est parfois prfrable, notamment si la
requte n'est pas dynamique.

Il est par exemple prfrable d'externaliser les requtes HQL lorsque cela est possible ce qui prsente plusieurs avantages :

faciliter de maintenance
faciliter pour recencer et optimiser les requtes
faciliter pour mettre les requtes en cache

Il est donc ncessaire de bien choisir entre HQL et l'API Criteria en fonction des besoins et de leur adquation avec ce que proposent les deux
solutions qui se recouvrent mais sont aussi complmentaires.

54.8. La mise jour d'une occurrence


Pour mettre jour une occurrence dans la source de donnes, il suffit d'appeler la mthode update() de la session en lui passant en paramtre l'objet
encapsulant les donnes.

Le mode de fonctionnement de cette mthode est similaire celui de la mthode save().

La mthode saveOrUpdate() laisse Hibernate choisir entre l'utilisation de la mthode save() ou update() en fonction de la valeur de l'identifiant dans la
classe encapsulant les donnes.

54.9. La suppression d'une ou plusieurs occurrences


La mthode delete() de la classe Session permet de supprimer une ou plusieurs occurrences en fonction de la version surcharge de la mthode utilise.

Pour supprimer une occurrence encapsule dans une classe, il suffit d'invoquer la mthode delete() en lui passant en paramtre l'instance de la classe.

Pour supprimer plusieurs occurrences, voire toutes, il faut passer en paramtre de la mthode delete(), une chane de caractres contenant la requte
HQL pour prciser les lments concerns par la suppression.

Exemple : suppression de toutes les occurrences de la table

1. session.delete("fromPersonnes");

54.10. Les relations

https://www.jmdoudoux.fr/java/dej/chaphibernate.htm 25/105
24/04/2017 DvelopponsenJavaHibernate
Un des fondements du modle de donnes relationnelles repose sur les relations qui peuvent intervenir entre une table et une ou plusieurs autres tables
ou la table elle mme.

Les relations utilisables dans le monde relationnel et le monde objet sont cependant diffrentes.

Les relations du monde objets possdent quelques caractristiques:

Elles sont ralises via des rfrences entre objets


Elles peuvent mettre en oeuvre l'hritage et le polymorphisme

Les relations du monde relationnel possdent quelques caractristiques:

Elles sont gres par des cls trangres et des jointures entre tables

Les caractristiques de ces deux modles sont assez diffrentes: le but d'un outil de type ORM comme Hibernate est de permettre de manipuler des
entits objets et de masquer au dveloppeur le monde relationnel en assurant un mapping entre les deux mondes. Cependant Hibernate n'assure pas en
automatique la gestion inverse des relations qui reste la charge du dveloppeur.

Hibernate propose de transcrire les relations du modle relationnel dans le modle objet. Il supporte plusieurs types de relations:

relation de type 1 - 1 (one-to-one)


relation de type 1 - n (one-to-many)
relation de type n - n (many-to-many)

Dans le fichier de mapping, il est ncessaire de dfinir les relations entre la table concerne et les tables avec lesquelles elle possde des relations.

Les relations peuvent aussi tre dfinies avec des annotations.

La version d'Hibernate utilise dans cette section est la 3.5.1.

La base de donnes utilise est une base MySQL version 4.1.9.

Chaque exemple possde plusieurs bibliothques dans son classpath: commons-collections-3.1.jar, dom4j-1.6.1.jar, hibernate-jpa-2.0-api-1.0.0.Final.jar,
hibernate3.jar, javassist-3.9.0.GA.jar, jta-1.1.jar, log4j-1.2.15.jar, mysql-connector-java-5.1.12-bin.jar, slf4j-api-1.5.8.jar, slf4j-log4j12-1.5.11.jar.

54.10.1. Les relations un / un

Dans ce type de relation, deux entits sont lies de faon n'avoir qu'une seule et unique occurrence l'une pour l'autre.

Dans l'exemple ci-dessus, chaque personne ne peut avoir qu'une seule adresse et une adresse ne peut appartenir qu' une seule personne.

Cette relation peut se traduire de plusieurs manires dans la base de donnes:

Une seule table qui contient les donnes de la personne et son adresse
Deux tables, une pour les personnes et une pour les adresses avec une cl primaire partage
Deux tables, une pour les personnes et une pour les adresses avec une cl trangre

Il y a plusieurs faons de traiter ce casavec une ou deux tables dans la base de donnes et Hibernate:

Deux tables et une relation One-to-One d'Hibernate


Une seule table avec un Component d'Hibernate

54.10.1.1. Le mapping avec un Component

Comme une personne ne peut avoir qu'une seule adresse, il est prfrable pour des raisons de performance de stocker les donnes des deux entits
dans une seule et mme table. Ceci vite d'avoir faire une jointure lors de l'accs aux donnes des deux entits.

La description de la table personne est la suivante:

Rsultat :

01. mysql>descpersonne;
02. +++++++
03. |Field|Type|Null|Key|Default|Extra|
04. +++++++
05. |Id|int(11)||PRI|NULL|auto_increment|
06. |Nom|varchar(255)|||||
07. |Prenom|varchar(255)|||||
08. |DateNais|date|YES||NULL||
09. |ligne1_adr|varchar(80)|||||
10. |ligne2_adr|varchar(80)|YES||NULL||
11. |cp_adr|varchar(5)|YES||NULL||
https://www.jmdoudoux.fr/java/dej/chaphibernate.htm 26/105
24/04/2017 DvelopponsenJavaHibernate
11. |cp_adr|varchar(5)|YES||NULL||
12. |ville_adr|varchar(80)|YES||NULL||
13. |ligne3_adr|varchar(80)|YES||NULL||
14. +++++++
15. 9rowsinset(0.00sec)

Le script DDL correspondant est le suivant:

Rsultat :

01. CREATETABLE`personne`(
02. `Id`int(11)NOTNULLauto_increment,
03. `Nom`varchar(255)NOTNULLdefault'',
04. `Prenom`varchar(255)NOTNULLdefault'',
05. `DateNais`datedefaultNULL,
06. `ligne1_adr`varchar(80)NOTNULLdefault'',
07. `ligne2_adr`varchar(80)defaultNULL,
08. `cp_adr`varchar(5)defaultNULL,
09. `ville_adr`varchar(80)defaultNULL,
10. `ligne3_adr`varchar(80)defaultNULL,
11. PRIMARYKEY(`Id`)
12. )ENGINE=InnoDBDEFAULTCHARSET=latin1AUTO_INCREMENT=0;

54.10.1.1.1. La configuration dans le fichier de mapping

Les classes qui encapsulent l'entit personne et les donnes de l'adresse sont de simples POJO.

Exemple :

01. packagecom.jmdoudoux.test.hibernate;
02.
03. publicclassPersonne{
04.
05. privateLongid;
06. privateStringnom;
07. privateStringprenom;
08. privateStringdateNais;
09. privateAdresseadresse;
10.
11. publicPersonne(Stringnom,Stringprenom,StringdateNais,Adresseadresse){
12. this.nom=nom;
13. this.prenom=prenom;
14. this.dateNais=dateNais;
15. this.adresse=adresse;
16. }
17.
18. publicPersonne(){
19. }
20.
21. publicStringgetNom(){
22. returnnom;
23. }
24.
25. publicvoidsetNom(Stringnom){
26. this.nom=nom;
27. }
28.
29. publicStringgetPrenom(){
30. returnprenom;
31. }
32.
33. publicvoidsetPrenom(Stringprenom){
34. this.prenom=prenom;
35. }
36.
37. publicStringgetDateNais(){
38. returndateNais;
39. }
40.
41. publicvoidsetDateNais(StringdateNais){
42. this.dateNais=dateNais;
43. }
44.
45. publicLonggetId(){
46. returnid;
47. }
48.
49. //AttentionlesetterestrequisparHibernate
50. publicvoidsetId(Longid){
51. this.id=id;
52. }
53.
54. publicAdressegetAdresse(){
55. returnadresse;
56. }
https://www.jmdoudoux.fr/java/dej/chaphibernate.htm 27/105
24/04/2017 DvelopponsenJavaHibernate
56. }
57.
58. publicvoidsetAdresse(Adresseadresse){
59. this.adresse=adresse;
60. }
61.
62. @Override
63. publicStringtoString(){
64. returnthis.id+":"+this.nom+""+this.prenom;
65. }
66. }

La classe Adresse ne possde pas de champ de type identifiant.

Exemple :

01. packagecom.jmdoudoux.test.hibernate;
02.
03. publicclassAdresse{
04.
05. privateStringligne1;
06. privateStringligne2;
07. privateStringcp;
08. privateStringville;
09. privateStringligne3;
10.
11. publicAdresse(Stringligne1,Stringligne2,Stringcp,Stringville,Stringligne3){
12. super();
13. this.ligne1=ligne1;
14. this.ligne2=ligne2;
15. this.cp=cp;
16. this.ville=ville;
17. this.ligne3=ligne3;
18. }
19.
20. publicAdresse(){
21. }
22.
23. //
24. //getteretsettersurleschampsdelaclasse
25. //
26.
27. }

Les donnes de l'adresse sont encapsules dans une classe Adresse : la dfinition des champs de cette classe est faite dans un lment de type
component du fichier de mapping de l'entit Personne (Personne.hbm.xml).

Exemple :

01. <?xmlversion="1.0"?>
02. <!DOCTYPEhibernatemappingPUBLIC
03. "//Hibernate/HibernateMappingDTD//EN"
04. "http://hibernate.sourceforge.net/hibernatemapping3.0.dtd">
05. <hibernatemapping>
06. <classname="com.jmdoudoux.test.hibernate.Personne"table="Personne">
07. <idname="id"column="id">
08. <generatorclass="increment"/>
09. </id>
10. <propertyname="nom"column="Nom"/>
11. <propertyname="prenom"column="Prenom"/>
12. <propertyname="dateNais"column="DateNais"/>
13. <componentname="adresse"class="com.jmdoudoux.test.hibernate.Adresse">
14. <propertyname="ligne1"column="ligne1_adr"/>
15. <propertyname="ligne2"column="ligne2_adr"/>
16. <propertyname="cp"column="cp_adr"/>
17. <propertyname="ville"column="ville_adr"/>
18. <propertyname="ligne3"column="ligne3_adr"/>
19. </component>
20. </class>
21. </hibernatemapping>

Le fichier de configuration d'Hibernate dfinit les paramtres de connexion la base de donnes et le fichier de mapping de l'entit Personne.

Exemple :

01. <?xmlversion='1.0'encoding='UTF8'?>
02. <!DOCTYPEhibernateconfigurationPUBLIC
03. "//Hibernate/HibernateConfigurationDTD3.0//EN"
04.
05. "http://hibernate.sourceforge.net/hibernateconfiguration3.0.dtd">
06. <hibernateconfiguration>
07. <sessionfactory>
08. <propertyname="connection.url">jdbc:mysql://localhost/mabdd<;/property>
09. <propertyname="connection.username">root</property>
10. <propertyname="connection.password"></property>
https://www.jmdoudoux.fr/java/dej/chaphibernate.htm 28/105
24/04/2017 DvelopponsenJavaHibernate
10. <propertyname="connection.password"></property>
11. <propertyname="connection.driver_class">com.mysql.jdbc.Driver</property>
12. <propertyname="dialect">org.hibernate.dialect.MySQLDialect</property>
13. <propertyname="transaction.factory_class">
14. org.hibernate.transaction.JDBCTransactionFactory</property>
15. <propertyname="current_session_context_class">thread</property>
16. <propertyname="hibernate.show_sql">true</property>
17. <mappingresource="com/jmdoudoux/test/hibernate/Personne.hbm.xml"></mapping>
18. </sessionfactory>
19. </hibernateconfiguration>

L'application de test est basique:

crer une instance de type Adresse,


crer une instance de type personne,
et sauvegarder la personne dans la base de donnes

Exemple :

01. packagecom.jmdoudoux.test.hibernate;
02.
03. importorg.hibernate.Session;
04. importorg.hibernate.SessionFactory;
05. importorg.hibernate.Transaction;
06. importorg.hibernate.cfg.Configuration;
07.
08. publicclassTestHibernate15{
09.
10. publicstaticvoidmain(Stringargs[]){
11. SessionFactorysessionFactory=newConfiguration().configure()
12. .buildSessionFactory();
13.
14. Transactiontransaction=null;
15. intindex=6;
16.
17. Sessionsession=sessionFactory.openSession();
18.
19. try{
20. transaction=session.beginTransaction();
21.
22. Adresseadresse=newAdresse("ligne1_"+index,"ligne2_"+index,"cp_"
23. +index,"ville"+index,"ligne3_"+index);
24. Personnepersonne=newPersonne("nom"+index,
25. "prenom_"+index,
26. null,
27. adresse);
28.
29. session.save(personne);
30. transaction.commit();
31.
32. System.out.println("Lanouvellepersonneaeteenregistree");
33.
34. }catch(Exceptione){
35. transaction.rollback();
36. e.printStackTrace();
37. }finally{
38. session.close();
39. }
40.
41. sessionFactory.close();
42. }
43. }

Lorsque la personne est enregistre dans la base de donnes, son adresse l'est aussi dans la table Personne.

Rsultat :

01. mysql>select*frompersonne;
02. ++++++++
03. ++
04. |Id|Nom|Prenom|DateNais|ligne1_adr|ligne2_adr|
05. cp_adr|ville_adr
06. |ligne3_adr|
07. ++++++++
08. ++
09. |1|nom6|prenom_6|NULL|ligne1_6|ligne2_6
10. |cp_6|ville6
11. |ligne3_6|
12. ++++++++
13. ++
14. 1rowinset(0.00sec)

https://www.jmdoudoux.fr/java/dej/chaphibernate.htm 29/105
24/04/2017 DvelopponsenJavaHibernate

54.10.1.1.2. La configuration avec les annotations

Le POJO qui encapsule une personne a quelques particularits relatives la relation avec l'adresse:

Il possde un champ priv de type Adresse

Le champ adresse est annot avec l'annotation @Embedded

Exemple :

01. packagecom.jmdoudoux.test.hibernate;
02.
03. importjavax.persistence.Column;
04. importjavax.persistence.Embedded;
05. importjavax.persistence.Entity;
06. importjavax.persistence.GeneratedValue;
07. importjavax.persistence.Id;
08. importjavax.persistence.Table;
09.
10. @Entity
11. @Table(name="personne")
12. publicclassPersonne{
13.
14. @Id
15. @GeneratedValue
16. @Column(name="Id")
17. privateLongid;
18.
19. @Column(name="Nom")
20. privateStringnom;
21.
22. @Column(name="Prenom")
23. privateStringprenom;
24.
25. @Column(name="DateNais")
26. privateStringdateNais;
27.
28. @Embedded
29. privateAdresseadresse;
30.
31. publicPersonne(Stringnom,Stringprenom,StringdateNais,Adresseadresse){
32. this.nom=nom;
33. this.prenom=prenom;
34. this.dateNais=dateNais;
35. this.adresse=adresse;
36. }
37.
38. publicPersonne(){
39. }
40.
41. publicLonggetId(){
42. returnid;
43. }
44.
45. publicAdressegetAdresse(){
46. returnadresse;
47. }
48.
49. publicvoidsetAdresse(Adresseadresse){
50. this.adresse=adresse;
51. }
52.
53. //
54. //getteretsettersurlesautreschampsdelaclasse
55. //
56.
57. @Override
58. publicStringtoString(){
59. returnthis.id+":"+this.nom+""+this.prenom;
60. }
61.
62. }

L'annotation @Embedded permet de prciser que les donnes de la classe Adresse seront stockes dans la table Personne comme un component
d'Hibernate.

Le POJO qui encapsule une adresse possde plusieurs particularits relatives la relation avec la personne:

La classe est annote avec l'annotation @Embeddable (elle n'est pas annote comme une entit avec les annotations @Entity et @Table)
La classe ne possde pas de champ de type identifiant

Exemple :

01. packagecom.jmdoudoux.test.hibernate;
02.
03. importjavax.persistence.Column;
04. importjavax.persistence.Embeddable;
05.
https://www.jmdoudoux.fr/java/dej/chaphibernate.htm 30/105
24/04/2017 DvelopponsenJavaHibernate
05.
06. @Embeddable
07. publicclassAdresse{
08.
09. @Column(name="ligne1_adr",nullable=false)
10. privateStringligne1;
11.
12. @Column(name="ligne2_adr")
13. privateStringligne2;
14.
15. @Column(name="cp_adr")
16. privateStringcp;
17.
18. @Column(name="ville_adr")
19. privateStringville;
20.
21. @Column(name="ligne3_adr")
22. privateStringligne3;
23.
24. publicAdresse(Stringligne1,Stringligne2,Stringcp,Stringville,
25. Stringligne3){
26. super();
27. this.ligne1=ligne1;
28. this.ligne2=ligne2;
29. this.cp=cp;
30. this.ville=ville;
31. this.ligne3=ligne3;
32. }
33.
34. publicAdresse(){
35. }
36.
37. //
38. //getteretsettersurleschampsdelaclasse
39. //
40.
41. }

L'annotation @Embeddable permet de prciser que la classe sera utilise comme un component. Un tel lment n'a pas d'identifiant puisque celui utilis
sera celui de l'entit englobante.

Le fichier de configuration d'Hibernate dfinit les paramtres de connexion la base de donnes et les deux classes qui encapsulent l'entit Personne
et le component Adresse.

Exemple :

01. <?xmlversion='1.0'encoding='UTF8'?>
02. <!DOCTYPEhibernateconfigurationPUBLIC
03. "//Hibernate/HibernateConfigurationDTD3.0//EN"
04. "http://hibernate.sourceforge.net/hibernateconfiguration3.0.dtd">
05. <hibernateconfiguration>
06. <sessionfactory>
07. <propertyname="connection.url">jdbc:mysql://localhost/mabdd<;/property>
08. <propertyname="connection.username">root</property>
09. <propertyname="connection.password"></property>
10. <propertyname="connection.driver_class">com.mysql.jdbc.Driver</property>
11. <propertyname="dialect">org.hibernate.dialect.MySQLDialect</property>
12. <propertyname="transaction.factory_class">
13. org.hibernate.transaction.JDBCTransactionFactory</property>
14. <propertyname="current_session_context_class">thread</property>
15. <propertyname="hibernate.show_sql">true</property>
16. <mappingclass="com.jmdoudoux.test.hibernate.Personne"></mapping>
17. <mappingclass="com.jmdoudoux.test.hibernate.Adresse"></mapping>
18. </sessionfactory>
19. </hibernateconfiguration>

L'application de test est basique:

crer une instance de type Adresse,


crer une instance de type Personne,
et sauvegarder la personne dans la base de donnes

Exemple :

01. packagecom.jmdoudoux.test.hibernate;
02.
03. importorg.hibernate.Session;
04. importorg.hibernate.SessionFactory;
05. importorg.hibernate.Transaction;
06. importorg.hibernate.cfg.AnnotationConfiguration;
07.
08. publicclassTestHibernate16{
09.
10. publicstaticvoidmain(Stringargs[]){
11. SessionFactorysessionFactory=newAnnotationConfiguration().configure()
12. .buildSessionFactory();
13. Transactiontransaction=null;
14. intindex=7;
https://www.jmdoudoux.fr/java/dej/chaphibernate.htm 31/105
24/04/2017 DvelopponsenJavaHibernate
14. intindex=7;
15.
16. Sessionsession=sessionFactory.openSession();
17.
18. try{
19. transaction=session.beginTransaction();
20.
21. Adresseadresse=newAdresse("ligne1_"+index,"ligne2_"+index,"cp_"
22. +index,"ville"+index,"ligne3_"+index);
23. Personnepersonne=newPersonne("nom"+index,
24. "prenom_"+index,
25. null,
26. adresse);
27.
28. session.save(personne);
29. transaction.commit();
30.
31. System.out.println("Lanouvellepersonneaeteenregistree");
32.
33. }catch(Exceptione){
34. transaction.rollback();
35. e.printStackTrace();
36. }finally{
37. session.close();
38. }
39.
40. sessionFactory.close();
41. }
42. }

Lorsque la personne est enregistre dans la base de donnes, son adresse l'est aussi dans la table Personne.

Rsultat :

01. mysql>select*frompersonne;
02. ++++++++
03. ++
04. |Id|Nom|Prenom|DateNais|ligne1_adr|ligne2_adr|cp_adr|ville_adr
05. |ligne3_adr|
06. ++++++++
07. ++
08. |2|nom7|prenom_7|NULL|ligne1_7|ligne2_7|cp_7|ville7
09. |ligne3_7|
10. ++++++++
11. ++
12. 1rowinset(0.00sec)

54.10.1.2. Le mapping avec une relation One-to-One avec cl primaire partage

La relation repose sur deux tables distinctes: une pour les personnes et une pour les adresses.

Chacune des deux tables possde un identifiant qui est sa cl primaire. La particularit est que la valeur des cls primaires est partage entre les deux
tables. L'identifiant de la table adresse n'est pas auto incrment et correspond la valeur de l'identifiant de la table personne.

Hibernate ne sait pas grer seul ce type de mapping: il sera ncessaire de l'aider en utilisant un mapping bidirectionnel qui permettra Hibernate de
connaitre la valeur de l'identifiant de la personne utiliser comme valeur de l'identifiant pour l'adresse afin que les deux correspondent.

La description de la table personne est la suivante:

Rsultat :

01. mysql>descpersonne;
02. +++++++
03. |Field|Type|Null|Key|Default|Extra|
04. +++++++
05. |Id|bigint(20)||PRI|NULL|auto_increment|
06. |Nom|varchar(255)|||||
07. |Prenom|varchar(255)|||||
08. |DateNais|date|YES||NULL||
09. +++++++
10. 4rowsinset(0.00sec)

Le script DDL correspondant est le suivant:

Rsultat :

1. CREATETABLE`personne`(
2. `Id`bigint(20)NOTNULLauto_increment,

3. `Nom`varchar(255)NOTNULLdefault'',
https://www.jmdoudoux.fr/java/dej/chaphibernate.htm 32/105
24/04/2017 DvelopponsenJavaHibernate
3. `Nom`varchar(255)NOTNULLdefault'',
4. `Prenom`varchar(255)NOTNULLdefault'',
5. `DateNais`datedefaultNULL,
6. PRIMARYKEY(`Id`)
7. )ENGINE=InnoDBDEFAULTCHARSET=latin1AUTO_INCREMENT=0;

La description de la table adresse est la suivante:

Rsultat :

01. mysql>descadresse;
02. +++++++
03. |Field|Type|Null|Key|Default|Extra|
04. +++++++
05. |id|bigint(20)||PRI|0||
06. |ligne1_adr|varchar(80)|||||
07. |ligne2_adr|varchar(80)|YES||NULL||
08. |cp_adr|varchar(5)|YES||NULL||
09. |ville_adr|varchar(80)|YES||NULL||
10. |ligne3_adr|varchar(80)|YES||NULL||
11. +++++++
12. 6rowsinset(0.11sec)

Le script DDL correspondant est le suivant:

Rsultat :

01. CREATETABLE`adresse`(
02. `id`bigint(20)NOTNULLdefault'0',
03. `ligne1_adr`varchar(80)NOTNULLdefault'',
04. `ligne2_adr`varchar(80)defaultNULL,
05. `cp_adr`varchar(5)defaultNULL,
06. `ville_adr`varchar(80)defaultNULL,
07. `ligne3_adr`varchar(80)defaultNULL,
08. PRIMARYKEY(`id`)
09. )ENGINE=InnoDBDEFAULTCHARSET=latin1;

54.10.1.2.1. La configuration dans le fichier de mapping

Les classes qui encapsulent les entits personne et adresse sont de simples POJO.

Exemple :

01. packagecom.jmdoudoux.test.hibernate;
02.
03. publicclassAdresse{
04.
05. privateLongid;
06. privateStringligne1;
07. privateStringligne2;
08. privateStringcp;
09. privateStringville;
10. privateStringligne3;
11.
12. privatePersonnepersonne;
13.
14. publicAdresse(Stringligne1,Stringligne2,Stringcp,Stringville,
15. Stringligne3){
16. super();
17. this.ligne1=ligne1;
18. this.ligne2=ligne2;
19. this.cp=cp;
20. this.ville=ville;
21. this.ligne3=ligne3;
22. }
23.
24. publicAdresse(){
25. }
26.
27. publicLonggetId(){
28. returnid;
29. }
30.
31. //setterrequisparHibernate
32. publicvoidsetId(Longid){
33. this.id=id;
34. }
35.
36. publicPersonnegetPersonne(){
37. returnpersonne;
https://www.jmdoudoux.fr/java/dej/chaphibernate.htm 33/105
24/04/2017 DvelopponsenJavaHibernate
37. returnpersonne;
38. }
39.
40. publicvoidsetPersonne(Personnepersonne){
41. this.personne=personne;
42. }
43.
44. //
45. //getteretsettersurlesautreschampsdelaclasse
46. //
47.
48. }

Exemple :

01. packagecom.jmdoudoux.test.hibernate;
02.
03. publicclassPersonne{
04.
05. privateLongid;
06. privateStringnom;
07. privateStringprenom;
08. privateStringdateNais;
09. privateAdresseadresse;
10.
11. publicPersonne(Stringnom,Stringprenom,StringdateNais,Adresseadresse){
12. this.nom=nom;
13. this.prenom=prenom;
14. this.dateNais=dateNais;
15. this.adresse=adresse;
16. }
17.
18. publicPersonne(){
19. }
20.
21. publicLonggetId(){
22. returnid;
23. }
24.
25. //AttentionlesetterestrequisparHibernate
26. publicvoidsetId(Longid){
27. this.id=id;
28. }
29.
30. publicAdressegetAdresse(){
31. returnadresse;
32. }
33.
34. publicvoidsetAdresse(Adresseadresse){
35. this.adresse=adresse;
36. }
37.
38. //
39. //getteretsettersurlesautreschampsdelaclasse
40. //
41.
42. @Override
43. publicStringtoString(){
44. returnthis.id+":"+this.nom+""+this.prenom;
45. }
46.
47. }

Le fichier de mapping de l'entit Personne (Personne.hbm.xml) contient un lment fils <one-to-one> pour dfinir la relation entre Personne et Adresse.

Exemple :

01. <?xmlversion="1.0"?>
02. <!DOCTYPEhibernatemappingPUBLIC
03. "//Hibernate/HibernateMappingDTD//EN"
04. "http://hibernate.sourceforge.net/hibernatemapping3.0.dtd">
05. <hibernatemapping>
06. <classname="com.jmdoudoux.test.hibernate.Personne"table="Personne">
07. <idname="id"column="id">
08. <generatorclass="increment"/>
09. </id>
10. <propertyname="nom"column="Nom"/>
11. <propertyname="prenom"column="Prenom"/>
12. <propertyname="dateNais"column="DateNais"/>
13. <onetoonename="adresse"class="com.jmdoudoux.test.hibernate.Adresse"
14. cascade="saveupdate"/>
15. </class>
16. </hibernatemapping>

Le fichier de mapping de l'entit Adresse (Adresse.hbm.xml) possde plusieurs caractristiques lies au type de la relation utilise avec l'entit
Personne:

https://www.jmdoudoux.fr/java/dej/chaphibernate.htm 34/105
24/04/2017 DvelopponsenJavaHibernate
Le champ identifiant id est dfini avec un gnrateur de type foreign avec un paramtre qui prcise que la valeur sera celle de l'identifiant du
champ personne
La relation inverse avec Personne est dfinie avec un tag <one-to-one> avec l'attribut constrained ayant la valeur true

Exemple :

01. <?xmlversion="1.0"?>
02. <!DOCTYPEhibernatemappingPUBLIC
03. "//Hibernate/HibernateMappingDTD//EN"
04. "http://hibernate.sourceforge.net/hibernatemapping3.0.dtd">
05. <hibernatemapping>
06. <classname="com.jmdoudoux.test.hibernate.Adresse"table="Adresse">
07.
08. <idname="id"column="Id">
09. <generatorclass="foreign">
10. <paramname="property">personne</param>
11. </generator>
12. </id>
13. <propertyname="ligne1"column="ligne1_adr"/>
14. <propertyname="ligne2"column="ligne2_adr"/>
15. <propertyname="cp"column="cp_adr"/>
16. <propertyname="ville"column="ville_adr"/>
17. <propertyname="ligne3"column="ligne3_adr"/>
18. <onetoonename="personne"class="com.jmdoudoux.test.hibernate.Personne"
19. constrained="true"/>
20. </class>
21. </hibernatemapping>

Le fichier de configuration d'Hibernate dfinit les paramtres de connexion la base de donnes et les deux fichiers de mapping des entits.

Exemple :

01. <?xmlversion='1.0'encoding='UTF8'?>
02. <!DOCTYPEhibernateconfigurationPUBLIC
03. "//Hibernate/HibernateConfigurationDTD3.0//EN"
04. "http://hibernate.sourceforge.net/hibernateconfiguration3.0.dtd">
05. <hibernateconfiguration>
06. <sessionfactory>
07. <propertyname="connection.url">jdbc:mysql://localhost/mabdd<;/property>
08. <propertyname="connection.username">root</property>
09. <propertyname="connection.password"></property>
10. <propertyname="connection.driver_class">com.mysql.jdbc.Driver</property>
11. <propertyname="dialect">org.hibernate.dialect.MySQLDialect</property>
12. <propertyname="transaction.factory_class">
13. org.hibernate.transaction.JDBCTransactionFactory</property>
14. <propertyname="current_session_context_class">thread</property>
15. <propertyname="hibernate.show_sql">true</property>
16. <mappingresource="com/jmdoudoux/test/hibernate/Personne.hbm.xml"></mapping>
17. <mappingresource="com/jmdoudoux/test/hibernate/Adresse.hbm.xml"></mapping>
18.
19. </sessionfactory>
20. </hibernateconfiguration>

L'application de test est basique:

crer une instance de type Adresse,


crer une instance de type Personne,
assurer le bon fonctionnement du lien bidirectionnel en fournissant une rfrence de l'objet Personne l'instance de l'adresse. Ceci doit tre
fait manuellement car Hibernate ne prend pas en charge automatiquement les liens bidirectionnels
et sauvegarder la personne dans la base de donnes

Exemple :

01. packagecom.jmdoudoux.test.hibernate;
02.
03. importorg.hibernate.Session;
04. importorg.hibernate.SessionFactory;
05. importorg.hibernate.Transaction;
06. importorg.hibernate.cfg.Configuration;
07.
08. publicclassTestHibernate11{
09.
10. publicstaticvoidmain(Stringargs[]){
11. SessionFactorysessionFactory=newConfiguration().configure()
12. .buildSessionFactory();
13. Transactiontransaction=null;
14. intindex=3;
15.
16. Sessionsession=sessionFactory.openSession();
17.
18. try{
19. transaction=session.beginTransaction();
20.
21. Adresseadresse=newAdresse("ligne1_"+index,"ligne2_"+index,"cp_"
22. +index,"ville"+index,"ligne3_"+index);
23. Personnepersonne=newPersonne("nom"+index,
https://www.jmdoudoux.fr/java/dej/chaphibernate.htm 35/105
24/04/2017 DvelopponsenJavaHibernate
23. Personnepersonne=newPersonne("nom"+index,
24. "prenom_"+index,
25. null,
26. adresse);
27. adresse.setPersonne(personne);
28.
29. session.save(personne);
30. transaction.commit();
31.
32. System.out.println("Lanouvellepersonneaeteenregistree");
33.
34. }catch(Exceptione){
35. transaction.rollback();
36. e.printStackTrace();
37. }finally{
38. session.close();
39. }
40.
41. sessionFactory.close();
42. }
43. }

Lorsque la personne est enregistre dans la base de donnes, son adresse l'est aussi avec comme identifiant la valeur de l'identifiant de la personne.

Rsultat :

01. mysql>select*frompersonne;
02. +++++
03. |Id|Nom|Prenom|DateNais|
04. +++++
05. |1|nom3|prenom_3|NULL|
06. +++++
07. 1rowinset(0.00sec)
08.
09. mysql>select*fromadresse;
10. +++++++
11. |id|ligne1_adr|ligne2_adr|cp_adr|ville_adr|ligne3_adr|
12. +++++++
13. |1|ligne1_3|ligne2_3|cp_3|ville3|ligne3_3|
14. +++++++
15. 1rowinset(0.00sec)

54.10.1.2.2. La configuration avec les annotations

Le POJO qui encapsule une personne a quelques particularits relatives la relation avec l'adresse:

Il possde un champ priv de type Adresse


Le champ adresse est annot avec les annotations @OneToOne et @PrimaryKeyJoin

Exemple :

01. packagecom.jmdoudoux.test.hibernate;
02.
03. importjavax.persistence.CascadeType;
04. importjavax.persistence.Column;
05. importjavax.persistence.Entity;
06. importjavax.persistence.GeneratedValue;
07. importjavax.persistence.Id;
08. importjavax.persistence.OneToOne;
09. importjavax.persistence.PrimaryKeyJoinColumn;
10. importjavax.persistence.Table;
11.
12. @Entity
13. @Table(name="personne")
14. publicclassPersonne{
15.
16. @Id
17. @GeneratedValue
18. @Column(name="Id")
19. privateLongid;
20.
21. @Column(name="Nom")
22. privateStringnom;
23.
24. @Column(name="Prenom")
25. privateStringprenom;
26.
27. @Column(name="DateNais")
28. privateStringdateNais;
29.
30. @OneToOne(cascade=CascadeType.ALL)
31. @PrimaryKeyJoinColumn
32. privateAdresseadresse;
33.
https://www.jmdoudoux.fr/java/dej/chaphibernate.htm 36/105
24/04/2017 DvelopponsenJavaHibernate
33.
34. publicPersonne(Stringnom,Stringprenom,StringdateNais,Adresseadresse){
35. this.nom=nom;
36. this.prenom=prenom;
37. this.dateNais=dateNais;
38. this.adresse=adresse;
39. }
40.
41. publicPersonne(){
42. }
43.
44. publicLonggetId(){
45. returnid;
46. }
47.
48. publicAdressegetAdresse(){
49. returnadresse;
50. }
51.
52. publicvoidsetAdresse(Adresseadresse){
53. this.adresse=adresse;
54. }
55.
56. //
57. //getteretsettersurlesautreschampsdelaclasse
58. //
59.
60. @Override
61. publicStringtoString(){
62. returnthis.id+":"+this.nom+""+this.prenom;
63. }
64.
65. }

Si le champ adresse n'est pas annot avec l'annotation @PrimaryKeyJoin, alors une exception de type org.hibernate.id.IdentifierGenerationException
avec le message null id generated for:class com.jmdoudoux.test.hibernate.Adresse est leve l'excution.

Le POJO qui encapsule une adresse possde plusieurs particularits relatives la relation avec la personne:

Le champ identifiant de l'entit est annot avec @GeneratedValue et @GenericGenerator pour indiquer Hibernate que la valeur du champ id
doit tre obtenue partie de la valeur du champ id de la proprit personne
Un champ de type Personne permet une relation bidirectionnelle annote avec @OneToOne
Un setter sur le champ personne permettra d'assurer la cohsion de la relation par le dveloppeur

Exemple :

01. packagecom.jmdoudoux.test.hibernate;
02.
03. importjavax.persistence.Column;
04. importjavax.persistence.Entity;
05. importjavax.persistence.GeneratedValue;
06. importjavax.persistence.Id;
07. importjavax.persistence.OneToOne;
08. importjavax.persistence.Table;
09.
10. importorg.hibernate.annotations.Parameter;
11.
12. @Entity
13. @Table(name="adresse")
14. publicclassAdresse{
15.
16. @Id
17. @GeneratedValue(generator="adresseGenerator")
18. @org.hibernate.annotations.GenericGenerator(name="adresseGenerator",
19. strategy="foreign",parameters=@Parameter(name="property",value="personne"))
20. @Column(name="id")
21. privateLongid;
22.
23. @Column(name="ligne1_adr",nullable=false)
24. privateStringligne1;
25.
26. @Column(name="ligne2_adr")
27. privateStringligne2;
28.
29. @Column(name="cp_adr")
30. privateStringcp;
31.
32. @Column(name="ville_adr")
33. privateStringville;
34.
35. @Column(name="ligne3_adr")
36. privateStringligne3;
37.
38. @OneToOne(mappedBy="adresse")
39. privatePersonnepersonne;
40.
41. publicAdresse(Stringligne1,Stringligne2,Stringcp,Stringville,
42. Stringligne3){
43. super();
44. this.ligne1=ligne1;
45. this.ligne2=ligne2;

46. this.cp=cp;
https://www.jmdoudoux.fr/java/dej/chaphibernate.htm 37/105
24/04/2017 DvelopponsenJavaHibernate
46. this.cp=cp;
47. this.ville=ville;
48. this.ligne3=ligne3;
49. }
50.
51. publicAdresse(){
52. }
53.
54. publicLonggetId(){
55. returnid;
56. }
57.
58. publicPersonnegetPersonne(){
59. returnpersonne;
60. }
61.
62. publicvoidsetPersonne(Personnepersonne){
63. this.personne=personne;
64. }
65.
66. //
67. //getteretsettersurlesautreschampsdelaclasse
68. //
69.
70. }

Le fichier de configuration d'Hibernate dfinit les paramtres de connexion la base de donnes et les deux classes qui encapsulent des entits.

Exemple :

01. <?xmlversion='1.0'encoding='UTF8'?>
02. <!DOCTYPEhibernateconfigurationPUBLIC
03. "//Hibernate/HibernateConfigurationDTD3.0//EN"
04. "http://hibernate.sourceforge.net/hibernateconfiguration3.0.dtd">
05. <hibernateconfiguration>
06. <sessionfactory>
07. <propertyname="connection.url">jdbc:mysql://localhost/mabdd<;/property>
08. <propertyname="connection.username">root</property>
09. <propertyname="connection.password"></property>
10. <propertyname="connection.driver_class">com.mysql.jdbc.Driver</property>
11. <propertyname="dialect">org.hibernate.dialect.MySQLDialect</property>
12. <propertyname="transaction.factory_class">
13. org.hibernate.transaction.JDBCTransactionFactory</property>
14. <propertyname="current_session_context_class">thread</property>
15. <propertyname="hibernate.show_sql">true</property>
16. <mappingclass="com.jmdoudoux.test.hibernate.Personne"></mapping>
17. <mappingclass="com.jmdoudoux.test.hibernate.Adresse"></mapping>
18.
19. </sessionfactory>
20. </hibernateconfiguration>

L'application de test est basique:

crer une instance de type Adresse,


crer une instance de type Personne,
assurer le bon fonctionnement du lien bidirectionnel en fournissant une rfrence de l'objet Personne l'instance de l'adresse. Ceci doit tre
fait manuellement car Hibernate ne prend pas en charge automatiquement les liens bidirectionnels
et sauvegarder la personne dans la base de donnes

Exemple :

01. packagecom.jmdoudoux.test.hibernate;
02.
03. importorg.hibernate.Session;
04. importorg.hibernate.SessionFactory;
05. importorg.hibernate.Transaction;
06. importorg.hibernate.cfg.AnnotationConfiguration;
07.
08. publicclassTestHibernate10{
09.
10. publicstaticvoidmain(Stringargs[]){
11. SessionFactorysessionFactory=newAnnotationConfiguration().configure()
12. .buildSessionFactory();
13. Transactiontransaction=null;
14. intindex=2;
15.
16. Sessionsession=sessionFactory.openSession();
17.
18. try{
19. transaction=session.beginTransaction();
20.
21. Adresseadresse=newAdresse("ligne1_"+index,"ligne2_"+index,"cp_"
22. +index,"ville"+index,"ligne3_"+index);
23. Personnepersonne=newPersonne("nom"+index,
24. "prenom_"+index,
25. null,
26. adresse);
27. adresse.setPersonne(personne);
https://www.jmdoudoux.fr/java/dej/chaphibernate.htm 38/105
24/04/2017 DvelopponsenJavaHibernate
27. adresse.setPersonne(personne);
28.
29. session.save(personne);
30. transaction.commit();
31.
32. System.out.println("Lanouvellepersonneaeteenregistree");
33.
34. }catch(Exceptione){
35. transaction.rollback();
36. e.printStackTrace();
37. }finally{
38. session.close();
39. }
40.
41. sessionFactory.close();
42. }
43. }

Lorsque la personne est enregistre dans la base de donnes, son adresse l'est aussi avec comme identifiant la valeur de l'identifiant de la personne.

Rsultat :

01. mysql>select*fromadresse;
02. +++++++
03. |id|ligne1_adr|ligne2_adr|cp_adr|ville_adr|ligne3_adr|
04. +++++++
05. |3|ligne1_1|ligne2_1|cp_1|ville1|ligne3_1|
06. +++++++
07. 1rowinset(0.00sec)
08.
09. mysql>select*frompersonne;
10. +++++
11. |Id|Nom|Prenom|DateNais|
12. +++++
13. |3|nom1|prenom_1|NULL|
14. +++++
15. 1rowinset(0.00sec)

Si la rfrence de l'instance de type Personne n'est pas fournie l'instance de type Adresse alors une exception de type
org.hibernate.id.IdentifierGenerationException avec le message attempted to assign id from null one-to-one property
[com.jmdoudoux.test.hibernate.Adresse.personne] est leve l'excution.

Si le gnrateur d'identifiant n'est pas correctement configur pour l'entit Adresse, alors une exception de type
org.hibernate.id.IdentifierGenerationException avec le message ids for this class must be manually assigned before calling save():
com.jmdoudoux.test.hibernate.Adresse lors de l'excution.

54.10.1.3. Le mapping avec une relation One-to-One avec cl trangre

La relation repose sur deux tables distinctes: une pour les personnes et une pour les adresses

Chacune des deux tables possde son propre identifiant et la relation entre les deux tables est assure par une cl trangre de la table personne vers
la table adresse.

Hibernate sait grer seul ce type de mapping s'il est unidirectionnel.

La description de la table personne est la suivante:

Rsultat :

01. mysql>descpersonne;
02. +++++++
03. |Field|Type|Null|Key|Default|Extra|
04. +++++++
05. |Id|int(11)||PRI|NULL|auto_increment|
06. |Nom|varchar(255)|||||
07. |Prenom|varchar(255)|||||
08. |DateNais|date|YES||NULL||
09. |adresse_id|int(11)|||0||
10. +++++++
11. 5rowsinset(0.00sec)

Le script DDL correspondant est le suivant:

Rsultat :

1. CREATETABLE`personne`(
2. `Id`int(11)NOTNULLauto_increment,
https://www.jmdoudoux.fr/java/dej/chaphibernate.htm 39/105
24/04/2017 DvelopponsenJavaHibernate
2. `Id`int(11)NOTNULLauto_increment,
3. `Nom`varchar(255)NOTNULLdefault'',
4. `Prenom`varchar(255)NOTNULLdefault'',
5. `DateNais`datedefaultNULL,
6. `adresse_id`int(11)NOTNULLdefault'0',
7. PRIMARYKEY(`Id`)
8. )ENGINE=InnoDBDEFAULTCHARSET=latin1AUTO_INCREMENT=0;

La description de la table adresse est la suivante:

Rsultat :

01. mysql>descadresse;
02. +++++++
03. |Field|Type|Null|Key|Default|Extra|
04. +++++++
05. |id|bigint(20)||PRI|NULL|auto_increment|
06. |ligne1_adr|varchar(80)|||||
07. |ligne2_adr|varchar(80)|YES||NULL||
08. |cp_adr|varchar(5)|YES||NULL||
09. |ville_adr|varchar(80)|YES||NULL||
10. |ligne3_adr|varchar(80)|YES||NULL||
11. +++++++
12. 6rowsinset(0.00sec)

Le script DDL correspondant est le suivant:

Rsultat :

01. CREATETABLE`adresse`(
02. `id`bigint(20)NOTNULLauto_increment,
03. `ligne1_adr`varchar(80)NOTNULLdefault'',
04. `ligne2_adr`varchar(80)defaultNULL,
05. `cp_adr`varchar(5)defaultNULL,
06. `ville_adr`varchar(80)defaultNULL,
07. `ligne3_adr`varchar(80)defaultNULL,
08. PRIMARYKEY(`id`)
09. )ENGINE=InnoDBDEFAULTCHARSET=latin1AUTO_INCREMENT=0;

54.10.1.3.1. La configuration dans le fichier de mapping

Les classes qui encapsulent les entits personne et adresse sont de simples POJO.

Exemple :

01. packagecom.jmdoudoux.test.hibernate;
02.
03. publicclassPersonne{
04.
05. privateLongid;
06. privateStringnom;
07. privateStringprenom;
08. privateStringdateNais;
09. privateAdresseadresse;
10.
11. publicPersonne(Stringnom,Stringprenom,StringdateNais,Adresseadresse){
12. this.nom=nom;
13. this.prenom=prenom;
14. this.dateNais=dateNais;
15. this.adresse=adresse;
16. }
17.
18. publicPersonne(){
19. }
20.
21. publicLonggetId(){
22. returnid;
23. }
24.
25. //AttentionlesetterestrequisparHibernate
26. publicvoidsetId(Longid){
27. this.id=id;
28. }
29.
30. publicAdressegetAdresse(){
31. returnadresse;
32. }
33.
34. publicvoidsetAdresse(Adresseadresse){

35. this.adresse=adresse;
https://www.jmdoudoux.fr/java/dej/chaphibernate.htm 40/105
24/04/2017 DvelopponsenJavaHibernate
35. this.adresse=adresse;
36. }
37.
38. //
39. //getteretsettersurlesautreschampsdelaclasse
40. //
41.
42. @Override
43. publicStringtoString(){
44. returnthis.id+":"+this.nom+""+this.prenom;
45. }
46.
47. }

Exemple :

01. packagecom.jmdoudoux.test.hibernate;
02. publicclassAdresse{
03. privateLongid;
04. privateStringligne1;
05. privateStringligne2;
06. privateStringcp;
07. privateStringville;
08. privateStringligne3;
09.
10. publicAdresse(Stringligne1,Stringligne2,Stringcp,Stringville,Stringligne3){
11. super();
12. this.ligne1=ligne1;
13. this.ligne2=ligne2;
14. this.cp=cp;
15. this.ville=ville;
16. this.ligne3=ligne3;
17. }
18.
19. publicAdresse(){
20. }
21.
22. publicLonggetId(){
23. returnid;
24. }
25.
26. //setterrequisparHibernate
27. publicvoidsetId(Longid){
28. this.id=id;
29. }
30.
31. //
32. //getteretsettersurlesautreschampsdelaclasse
33. //
34.
35. }

Le fichier de mapping de l'entit Personne (Personne.hbm.xml) contient un lment fils <many-to-one> pour dfinir la relation entre Personne et
Adresse: l'unicit de la relation est cependant garantie par la valeur true de l'attribut unique. Il faut aussi utiliser une proprit column pour prciser
la colonne qui va contenir la cl trangre vers la table adresse.

Exemple :

01. <?xmlversion="1.0"?>
02. <!DOCTYPEhibernatemappingPUBLIC
03. "//Hibernate/HibernateMappingDTD//EN"
04. "http://hibernate.sourceforge.net/hibernatemapping3.0.dtd">
05. <hibernatemapping>
06. <classname="com.jmdoudoux.test.hibernate.Personne"table="Personne">
07. <idname="id"column="Id">
08. <generatorclass="increment"/>
09. </id>
10. <propertyname="nom"column="Nom"/>
11. <propertyname="prenom"column="Prenom"/>
12. <propertyname="dateNais"column="DateNais"/>
13. <manytoonename="adresse"class="com.jmdoudoux.test.hibernate.Adresse"
14. column="adresse_id"cascade="all"unique="true"/>
15. </class>
16. </hibernatemapping>

Le fichier de mapping de l'entit Adresse (Adresse.hbm.xml) ne contient aucune particularit.

Exemple :

01. <?xmlversion="1.0"?>
02. <!DOCTYPEhibernatemappingPUBLIC
03. "//Hibernate/HibernateMappingDTD//EN"
04. "http://hibernate.sourceforge.net/hibernatemapping3.0.dtd">
05. <hibernatemapping>
06. <classname="com.jmdoudoux.test.hibernate.Adresse"table="Adresse">
07. <idname="id">
https://www.jmdoudoux.fr/java/dej/chaphibernate.htm 41/105
24/04/2017 DvelopponsenJavaHibernate
07. <idname="id">
08. <generatorclass="increment"/>
09. </id>
10. <propertyname="ligne1"column="ligne1_adr"/>
11. <propertyname="ligne2"column="ligne2_adr"/>
12. <propertyname="cp"column="cp_adr"/>
13. <propertyname="ville"column="ville_adr"/>
14. <propertyname="ligne3"column="ligne3_adr"/>
15. </class>
16. </hibernatemapping>

Le fichier de configuration d'Hibernate dfinit les paramtres de connexion la base de donnes et les deux fichiers de mapping des entits.

Exemple :

01. <?xmlversion='1.0'encoding='UTF8'?>
02. <!DOCTYPEhibernateconfigurationPUBLIC
03. "//Hibernate/HibernateConfigurationDTD3.0//EN"
04. "http://hibernate.sourceforge.net/hibernateconfiguration3.0.dtd">
05. <hibernateconfiguration>
06. <sessionfactory>
07. <propertyname="connection.url">jdbc:mysql://localhost/mabdd<;/property>
08. <propertyname="connection.username">root</property>
09. <propertyname="connection.password"></property>
10. <propertyname="connection.driver_class">com.mysql.jdbc.Driver</property>
11. <propertyname="dialect">org.hibernate.dialect.MySQLDialect</property>
12. <propertyname="transaction.factory_class">
13. org.hibernate.transaction.JDBCTransactionFactory</property>
14. <propertyname="current_session_context_class">thread</property>
15. <propertyname="hibernate.show_sql">true</property>
16. <mappingresource="com/jmdoudoux/test/hibernate/Personne.hbm.xml"></mapping>
17. <mappingresource="com/jmdoudoux/test/hibernate/Adresse.hbm.xml"></mapping>
18.
19. </sessionfactory>
20. </hibernateconfiguration>

L'application de test est basique:

crer une instance de type Adresse,


crer une instance de type Personne,
et sauvegarder la personne dans la base de donnes

Exemple :

01. packagecom.jmdoudoux.test.hibernate;
02.
03. importorg.hibernate.Session;
04. importorg.hibernate.SessionFactory;
05. importorg.hibernate.Transaction;
06. importorg.hibernate.cfg.Configuration;
07.
08. publicclassTestHibernate12{
09.
10. publicstaticvoidmain(Stringargs[]){
11. SessionFactorysessionFactory=newConfiguration().configure()
12. .buildSessionFactory();
13. Transactiontransaction=null;
14. intindex=4;
15.
16. Sessionsession=sessionFactory.openSession();
17.
18. try{
19. transaction=session.beginTransaction();
20.
21. Adresseadresse=newAdresse("ligne1_"+index,"ligne2_"+index,"cp_"
22. +index,"ville"+index,"ligne3_"+index);
23. Personnepersonne=newPersonne("nom_"+index,
24. "prenom_"+index,
25. null,
26. adresse);
27.
28. session.save(personne);
29. transaction.commit();
30.
31. System.out.println("Lanouvellepersonneaeteenregistree");
32.
33. }catch(Exceptione){
34. transaction.rollback();
35. e.printStackTrace();
36. }finally{
37. session.close();
38. }
39.
40. sessionFactory.close();
41. }
42. }

https://www.jmdoudoux.fr/java/dej/chaphibernate.htm 42/105
24/04/2017 DvelopponsenJavaHibernate

Lorsque la personne est enregistre dans la base de donnes, son adresse l'est aussi. Les nouvelles occurrences des tables Personne et Adresse
possdent chacun leur propre identifiant et celui de l'adresse est report dans le champ adresse_id de la table Personne.

Rsultat :

01. mysql>select*frompersonne;
02. ++++++
03. |Id|Nom|Prenom|DateNais|adresse_id|
04. ++++++
05. |1|nom_4|prenom_4|NULL|8|
06. ++++++
07. 1rowinset(0.82sec)
08.
09. mysql>select*fromadresse;
10. +++++++
11. |id|ligne1_adr|ligne2_adr|cp_adr|ville_adr|ligne3_adr|
12. +++++++
13. |8|ligne1_4|ligne2_4|cp_4|ville4|ligne3_4|
14. +++++++
15. 1rowinset(0.00sec)

54.10.1.3.2. La configuration avec les annotations

Le POJO qui encapsule une personne a quelques particularits relatives la relation avec l'adresse:

Il possde un champ priv de type Adresse


Le champ adresse est annot avec les annotations @OneToOne et @JoinColumn

Exemple :

01. packagecom.jmdoudoux.test.hibernate;
02.
03. importjavax.persistence.CascadeType;
04. importjavax.persistence.Column;
05. importjavax.persistence.Entity;
06. importjavax.persistence.GeneratedValue;
07. importjavax.persistence.Id;
08. importjavax.persistence.JoinColumn;
09. importjavax.persistence.OneToOne;
10. importjavax.persistence.Table;
11.
12. @Entity
13. @Table(name="personne")
14. publicclassPersonne{
15.
16. @Id
17. @GeneratedValue
18. @Column(name="Id")
19. privateLongid;
20.
21. @Column(name="Nom")
22. privateStringnom;
23.
24. @Column(name="Prenom")
25. privateStringprenom;
26.
27. @Column(name="DateNais")
28. privateStringdateNais;
29.
30. @OneToOne(cascade=CascadeType.ALL)
31. @JoinColumn(name="adresse_id")
32. privateAdresseadresse;
33.
34. publicPersonne(Stringnom,Stringprenom,StringdateNais,Adresseadresse){
35. this.nom=nom;
36. this.prenom=prenom;
37. this.dateNais=dateNais;
38. this.adresse=adresse;
39. }
40.
41. publicPersonne(){
42. }
43.
44. publicLonggetId(){
45. returnid;
46. }
47.
48. publicAdressegetAdresse(){
49. returnadresse;
50. }
51.
52. publicvoidsetAdresse(Adresseadresse){
53. this.adresse=adresse;

54. }
https://www.jmdoudoux.fr/java/dej/chaphibernate.htm 43/105
24/04/2017 DvelopponsenJavaHibernate
54. }
55.
56. //
57. //getteretsettersurlesautreschampsdelaclasse
58. //
59.
60. @Override
61. publicStringtoString(){
62. returnthis.id+":"+this.nom+""+this.prenom;
63. }
64. }

Le POJO qui encapsule une adresse ne possde aucune particularit relative la relation avec la personne. Il est cependant possible d'ajouter au besoin
une relation inverse d'adresse vers personne en ajoutant un champ Personne annot avec l'annotation @one-to-one possdant un attribut mappedBy qui
possde comme valeur le nom du champ de l'adresse dans l'entit Personne.

Dans ce cas, la gestion de l'alimentation du champ personne est la charge du dveloppeur en utilisant le setter sur le champ personne.

L'identifiant de l'entit est annot avec @GeneratedValue

Exemple :

01. packagecom.jmdoudoux.test.hibernate;
02.
03. importjavax.persistence.Column;
04. importjavax.persistence.Entity;
05. importjavax.persistence.GeneratedValue;
06. importjavax.persistence.Id;
07. importjavax.persistence.Table;
08.
09. @Entity
10. @Table(name="adresse")
11. publicclassAdresse{
12.
13. @Id
14. @GeneratedValue
15. @Column(name="id")
16. privateLongid;
17.
18. @Column(name="ligne1_adr",nullable=false)
19. privateStringligne1;
20.
21. @Column(name="ligne2_adr")
22. privateStringligne2;
23.
24. @Column(name="cp_adr")
25. privateStringcp;
26.
27. @Column(name="ville_adr")
28. privateStringville;
29.
30. @Column(name="ligne3_adr")
31. privateStringligne3;
32.
33. publicAdresse(Stringligne1,Stringligne2,Stringcp,Stringville,
34. Stringligne3){
35. super();
36. this.ligne1=ligne1;
37. this.ligne2=ligne2;
38. this.cp=cp;
39. this.ville=ville;
40. this.ligne3=ligne3;
41. }
42.
43. publicAdresse(){
44. }
45.
46. publicLonggetId(){
47. returnid;
48. }
49.
50. //
51. //getteretsettersurlesautreschampsdelaclasse
52. //
53.
54. }

Le fichier de configuration d'Hibernate dfinit les paramtres de connexion la base de donnes et les deux classes qui encapsulent des entits.

Exemple :

01. <?xmlversion='1.0'encoding='UTF8'?>
02. <!DOCTYPEhibernateconfigurationPUBLIC
03. "//Hibernate/HibernateConfigurationDTD3.0//EN"
04. "http://hibernate.sourceforge.net/hibernateconfiguration3.0.dtd">
05. <hibernateconfiguration>
06. <sessionfactory>
07. <propertyname="connection.url">jdbc:mysql://localhost/mabdd<;/property>
08. <propertyname="connection.username">root</property>
https://www.jmdoudoux.fr/java/dej/chaphibernate.htm 44/105
24/04/2017 DvelopponsenJavaHibernate
08. <propertyname="connection.username">root</property>
09. <propertyname="connection.password"></property>
10. <propertyname="connection.driver_class">com.mysql.jdbc.Driver</property>
11. <propertyname="dialect">org.hibernate.dialect.MySQLDialect</property>
12. <propertyname="transaction.factory_class">
13. org.hibernate.transaction.JDBCTransactionFactory</property>
14. <propertyname="current_session_context_class">thread</property>
15. <propertyname="hibernate.show_sql">true</property>
16. <mappingclass="com.jmdoudoux.test.hibernate.Personne"></mapping>
17. <mappingclass="com.jmdoudoux.test.hibernate.Adresse"></mapping>
18.
19. </sessionfactory>
20. </hibernateconfiguration>

L'application de test est basique:

crer une instance de type Adresse,


crer une instance de type Personne,
et sauvegarder la personne dans la base de donnes

Exemple :

01. packagecom.jmdoudoux.test.hibernate;
02.
03. importorg.hibernate.Session;
04. importorg.hibernate.SessionFactory;
05. importorg.hibernate.Transaction;
06. importorg.hibernate.cfg.AnnotationConfiguration;
07.
08. publicclassTestHibernate14{
09.
10. publicstaticvoidmain(Stringargs[]){
11. SessionFactorysessionFactory=newAnnotationConfiguration().configure()
12. .buildSessionFactory();
13. Transactiontransaction=null;
14. intindex=5;
15.
16. Sessionsession=sessionFactory.openSession();
17.
18. try{
19. transaction=session.beginTransaction();
20.
21. Adresseadresse=newAdresse("ligne1_"+index,"ligne2_"+index,"cp_"
22. +index,"ville"+index,"ligne3_"+index);
23. Personnepersonne=newPersonne("nom"+index,
24. "prenom_"+index,
25. null,
26. adresse);
27. session.save(personne);
28. transaction.commit();
29.
30. System.out.println("Lanouvellepersonneaeteenregistree");
31.
32. }catch(Exceptione){
33. transaction.rollback();
34. e.printStackTrace();
35. }finally{
36. session.close();
37. }
38.
39. sessionFactory.close();
40. }
41. }

Lorsque la personne est enregistre dans la base de donnes, son adresse l'est aussi. Chaque nouvelle occurrence de la table Personne et de la table
Adresse possde son propre identifiant et celui de l'adresse est report dans le champ adresse_id de la table Personne.

Rsultat :

01. mysql>select*fromadresse;
02. +++++++
03. |id|ligne1_adr|ligne2_adr|cp_adr|ville_adr|ligne3_adr|
04. +++++++
05. |10|ligne1_5|ligne2_5|cp_5|ville5|ligne3_5|
06. +++++++
07. 1rowinset(0.00sec)
08.
09. mysql>select*frompersonne;
10. ++++++
11. |Id|Nom|Prenom|DateNais|adresse_id|
12. ++++++
13. |8|nom5|prenom_5|NULL|10|
14. ++++++
15. 1rowinset(0.00sec)

https://www.jmdoudoux.fr/java/dej/chaphibernate.htm 45/105
24/04/2017 DvelopponsenJavaHibernate

La suite de cette section sera dveloppe dans une version future de ce document

54.11. Le mapping de l'hritage de classes


Hibernate propose un support des trois stratgies de base pour le mapping d'hritage de classes:

une table par hirarchie de classes (Table Per Hierarchy) : une seule table est utilise. Elle possde une colonne supplmentaire qui sert de
discriminant en prcisant le type des donnes de la ligne
une table par classe concrte (Table Per Concrete class): chaque classe concrte correspond une table. Les champs communs sont dupliqus
dans chaque table fille
une table par sous-classe (Table Per Subclass) : chaque classe correspond une table. Les relations entre ces tables se font en utilisant des
relations par cls trangres. Il n'y a donc pas de colonnes dupliques. Chaque classe est mappe sa propre table.

Hibernate propose aussi une autre stratgie nomme une table par sous-classe avec discriminant.

Pour mapper une relation d'hritage dans le modle relationnel, il faut donc choisir une stratgie qui sera adapte en fonction des besoins.

Les exemples de cette section vont utiliser une hirarchie de classes compose d'une classe mre Compte et deux classes filles CompteEpargne et
CompteCourant.

La mme classe est utilise pour mettre en oeuvre des traitements avec les diffrentes stratgies de mapping.

Exemple :

001. packagecom.jmdoudoux.test.hibernate;
002.
003. importjava.math.BigDecimal;
004. importjava.util.List;
005. importorg.hibernate.Query;
006. importorg.hibernate.Session;
007. importorg.hibernate.SessionFactory;
008. importorg.hibernate.Transaction;
009. importorg.hibernate.cfg.Configuration;
010. importorg.hibernate.service.ServiceRegistry;
011. importorg.hibernate.service.ServiceRegistryBuilder;
012. importcom.jmdoudoux.test.hibernate.entity.Compte;
013. importcom.jmdoudoux.test.hibernate.entity.CompteCourant;
014. importcom.jmdoudoux.test.hibernate.entity.CompteEpargne;
015.
016. publicclassTestHibernate{
017.
018. privatestaticSessionFactorysessionFactory=null;
019.
020. publicstaticvoidmain(String[]args){
021. try{
022. ConfigurationhibernateConfig=newConfiguration().configure();
023. ServiceRegistryserviceRegistry=newServiceRegistryBuilder()
024. .applySettings(hibernateConfig.getProperties())
025. .buildServiceRegistry();
026. sessionFactory=hibernateConfig.buildSessionFactory(serviceRegistry);
027. creerComptes();
028. rechercherChaqueCompte();
029. rechercherTousLesComptes();
030. rechercheComptesPolymorphiques();
031. }catch(Throwableex){
032. ex.printStackTrace();
033. }finally{
034. sessionFactory.close();
https://www.jmdoudoux.fr/java/dej/chaphibernate.htm 46/105
24/04/2017 DvelopponsenJavaHibernate
034. sessionFactory.close();
035. }
036. }
037.
038. publicstaticTransactioncreerComptes(){
039. Sessionsession=sessionFactory.openSession();
040. Transactiontx=null;
041. try{
042. Comptecompte=newCompte();
043. compte.setNumero("000012345000");
044. compte.setSolde(BigDecimal.ZERO);
045. CompteCourantcompteCourant=newCompteCourant();
046. compteCourant.setNumero("000012345010");
047. compteCourant.setSolde(newBigDecimal("1200"));
048. compteCourant.setDecouvert(2000);
049. CompteEpargnecompteEpargne=newCompteEpargne();
050. compteEpargne.setNumero("000012345020");
051. compteEpargne.setSolde(newBigDecimal(8000));
052. compteEpargne.setTaux(newBigDecimal("2.10"));
053.
054. tx=session.beginTransaction();
055. session.save(compte);
056. session.save(compteCourant);
057. session.save(compteEpargne);
058. tx.commit();
059. }catch(RuntimeExceptione){
060. try{
061. tx.rollback();
062. }catch(RuntimeExceptionrbe){
063. rbe.printStackTrace();
064. }
065. throwe;
066. }finally{
067. if(session!=null)
068. session.close();
069. }
070. returntx;
071. }
072.
073. publicstaticvoidrechercherChaqueCompte(){
074. Sessionsession=sessionFactory.openSession();
075. Transactiontx=null;
076. try{
077. tx=session.beginTransaction();
078. System.out.println("Recherched'uncompte");
079. Comptecompte=(Compte)session.load(Compte.class,newInteger(1));
080. System.out.println(compte);
081. System.out.println();
082. System.out.println("Recherched'uncomptecourant");
083. CompteCourantcompteCourant=(CompteCourant)session.load(
084. CompteCourant.class,newInteger(2));
085. System.out.println(compteCourant);
086. System.out.println();
087. System.out.println("Recherchepolymorphiqued'uncompte");
088. compte=(Compte)session.load(Compte.class,newInteger(3));
089. System.out.println(compte);
090. System.out.println();
091. tx.commit();
092. }catch(RuntimeExceptione){
093. try{
094. tx.rollback();
095. }catch(RuntimeExceptionrbe){
096. rbe.printStackTrace();
097. }
098. throwe;
099. }finally{
100. if(session!=null)
101. session.close();
102. }
103. }
104.
105. publicstaticvoidrechercherTousLesComptes(){
106. Sessionsession=sessionFactory.openSession();
107. Transactiontx=null;
108. System.out.println("Recherchedetouslescomptes");
109. try{
110. tx=session.beginTransaction();
111. Queryquery=session.createQuery("fromCompte");
112. List<Compte>comptes=query.list();
113. for(Comptecompte:comptes){
114. System.out.println(compte);
115. }
116. System.out.println();
117. tx.commit();
118. }catch(RuntimeExceptione){
119. try{
120. tx.rollback();
121. }catch(RuntimeExceptionrbe){
122. rbe.printStackTrace();
123. }
124. throwe;
125. }finally{
126. if(session!=null)
127. session.close();
128. }
129. }
130.
131. publicstaticvoidrechercheComptesPolymorphiques(){
https://www.jmdoudoux.fr/java/dej/chaphibernate.htm 47/105
24/04/2017 DvelopponsenJavaHibernate
131. publicstaticvoidrechercheComptesPolymorphiques(){
132. Sessionsession=sessionFactory.openSession();
133. Transactiontx=null;
134. System.out.println("Recherchepolymorphiquedecomptes");
135. try{
136. tx=session.beginTransaction();
137. Queryquery=session
138. .createQuery("selectcfromComptecwherec.numerolike:numero");
139. query.setParameter("numero","000012345%");
140. List<Compte>comptes=query.list();
141. for(Comptecompte:comptes){
142. System.out.println(compte);
143. }
144. tx.commit();
145. }catch(RuntimeExceptione){
146. try{
147. tx.rollback();
148. }catch(RuntimeExceptionrbe){
149. rbe.printStackTrace();
150. }
151. throwe;
152. }finally{
153. if(session!=null)
154. session.close();
155. }
156. System.out.println();
157. }
158. }

La version d'Hibernate utilise est la 4.2.17.

54.11.1. XML

La dclaration du mapping dans un fichier XML utilise plusieurs tags en fonction de la stratgie utilise : <class>, <union-subclass>, <subclass> et <joined-
subclass>.

Il n'est pas possible de mixer l'utilisation du tag <subclass> et <joined-subclass> dans le mme tag <class>.

Les exemples des sections suivantes utilisent trois classes qui sont les entits du modle.

Exemple :

01. packagecom.jmdoudoux.test.hibernate.entity;
02.
03. importjava.math.BigDecimal;
04.
05. publicclassCompte{
06. protectedintid;
07. protectedStringnumero;
08. protectedBigDecimalsolde;
09.
10. publicintgetId(){
11. returnid;
12. }
13.
14. publicvoidsetId(intid){
15. this.id=id;
16. }
17.
18. publicStringgetNumero(){
19. returnnumero;
20. }
21.
22. publicvoidsetNumero(Stringnumero){
23. this.numero=numero;
24. }
25.
26. publicBigDecimalgetSolde(){
27. returnsolde;
28. }
29.
30. publicvoidsetSolde(BigDecimalsolde){
31. this.solde=solde;
32. }
33.
34. @Override
35. publicStringtoString(){
36. returnsuper.toString()+"[id="+id+",numero="+numero+",solde="
37. +solde+"]";
38. }
39. }

Exemple :

https://www.jmdoudoux.fr/java/dej/chaphibernate.htm 48/105
24/04/2017 DvelopponsenJavaHibernate
01. packagecom.jmdoudoux.test.hibernate.entity;
02.
03. publicclassCompteCourantextendsCompte{
04. protectedintdecouvert;
05.
06. publicintgetDecouvert(){
07. returndecouvert;
08. }
09.
10. publicvoidsetDecouvert(intdecouvert){
11. this.decouvert=decouvert;
12. }
13.
14. @Override
15. publicStringtoString(){
16. returnthis.getClass().getName()+"@"+System.identityHashCode(this)
17. +"CompteCourant[id="+id+",numero="+numero+",solde="+solde
18. +",decouvert="+decouvert+"]";
19. }
20. }

Exemple :

01. packagecom.jmdoudoux.test.hibernate.entity;
02.
03. importjava.math.BigDecimal;
04.
05. publicclassCompteEpargneextendsCompte{
06. protectedBigDecimaltaux;
07.
08. publicBigDecimalgetTaux(){
09. returntaux;
10. }
11.
12. publicvoidsetTaux(BigDecimaltaux){
13. this.taux=taux;
14. }
15.
16. @Override
17. publicStringtoString(){
18. returnthis.getClass().getName()+"@"+System.identityHashCode(this)
19. +"CompteEpargne[id="+id+",numero="+numero+",solde="
20. +solde+",taux="+taux+"]";
21. }
22. }

La configuration d'Hibernate est stocke dans le fichier hibernate.cfg.xml.

Exemple :

01. <?xmlversion='1.0'encoding='utf8'?>
02. <!DOCTYPEhibernateconfigurationSYSTEM
03. "http://www.hibernate.org/dtd/hibernateconfiguration3.0.dtd">
04. <hibernateconfiguration>
05. <sessionfactory>
06. <!Databaseconnectionsettings>
07. <propertyname="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
08. <propertyname="hibernate.connection.url">jdbc:mysql://localhost:3307/mabdd</property>
09. <propertyname="hibernate.connection.username">root</property>
10. <propertyname="hibernate.connection.password">root</property>
11. <propertyname="hibernate.connection.pool_size">1</property>
12. <propertyname="hibernate.dialect">org.hibernate.dialect.MySQL5Dialect</property>
13. <propertyname="hibernate.current_session_context_class">thread</property>
14. <!Cachedesecondniveaudsactiv>
15. <propertyname="hibernate.cache.provider_class">
16. org.hibernate.cache.internal.NoCacheProvider</property>
17. <!AfficherlesrequtesSQLexcutessurlasortiestandard>
18. <propertyname="hibernate.show_sql">true</property>
19.
20. <propertyname="hbm2ddl.auto">create</property>
21.
22. <mappingresource="Compte.hbm.xml"/>
23. </sessionfactory>
24. </hibernateconfiguration>

Remarque : La proprit hbm2dll.auto est initialise avec la valeur create pour demander Hibernate de recrer automatiquement les tables chaque
excution.

54.11.1.1. XML, une table par hirarchie de classes

https://www.jmdoudoux.fr/java/dej/chaphibernate.htm 49/105
24/04/2017 DvelopponsenJavaHibernate
Pour dfinir le mapping d'un hritage utilisant le modle une table par hirarchie de classe, il faut utiliserdans un mme fichier hbm :

un tag <class> pour le mapping classe mre


un tag <subclass> pour le mapping de chaque classe fille

Le tag <class> possde l'attribut polymorphism qui peut prendre deux valeurs (implicit ou explicit) et permet de prciser le type de requte
polymorphique.

L'attribut abstract permet de prciser si la classe mre de la hirarchie est abstraite. Les valeurs possibles sont true et false

Le tag <discriminator> permet de prciser la colonne qui servira de discriminant.

Il possde plusieurs attributs:

column Prciser le nom de la colonne dans la table, par dfaut c'est le nom de la classe

formula Une expression SQL qui sera excute pour obtenir la valeur. Optionnel

type Prciser le type de la donne. Optionnel: par dfaut, String

not-null true (par dfaut) ou false

length Prciser la taille de la colonne

force true ou false. Optionnel: par dfaut, false

insert Prciser si la colonne doit tre incluse dans les instructions insert: true ou false. Optionnel: par dfaut, true

Le tag <subclass> possde plusieurs attributs:

entity-name Optionnel

name Nom pleinement qualifi de la classe de l'entit

proxy Interface ou classe qui est utilise pour la cration des proxys. Optionnel

discriminator-value Une valeur qui permet de distinguer chaque entit. Optionnel: par dfaut c'est le nom de la classe

dynamic-update true ou false (par dfaut)

dynamic-insert true ou false (par dfaut)

select-before-update true ou false (par dfaut)

extends Nom de la superclasse

lazy Activation du lazy fetching: true ou false. Optionnel: par dfaut true

abstract true ou false

persister Prciser un ClassPersister personnalis. Optionnel

batch-size Dfinir le nombre d'occurrences rcupres par lot. Optionnel

node

Les tags <class> et <subclass> possdent un attribut discriminator-value qui permet de prciser la valeur de la colonne discriminante qui sera utilise
pour la classe. Il n'est pas ncessaire de fournir une valeur l'attribut discriminator-value pour les classes abstraites.

La colonne discriminator ne doit pas tre dfinie dans la classe Java correspondante: c'est une colonne technique qui n'est utilise que par Hibernate
et la base de donnes.

Exemple :

01. <?xmlversion="1.0"encoding="UTF8"?>
02. <!DOCTYPEhibernatemappingPUBLIC"//Hibernate/HibernateMappingDTD//EN"
03. "http://www.hibernate.org/dtd/hibernatemapping3.0.dtd">
04.
05. <hibernatemapping>
06. <classname="com.jmdoudoux.test.hibernate.entity.Compte"
07. table="compte"discriminatorvalue="Compte">
08. <idname="id"column="id"type="int">
09. <generatorclass="native"/>
10. </id>
11. <discriminatorcolumn="DTYPE"type="string"/>
12.
13. <propertyname="numero"column="numero"type="string"/>
14. <propertyname="solde"column="solde"type="big_decimal"/>
15. <subclassname="com.jmdoudoux.test.hibernate.entity.CompteCourant"
16. discriminatorvalue="CompteCourant">
17. <propertyname="decouvert"column="decouvert"type="int"/>
18. </subclass>
19. <subclassname="com.jmdoudoux.test.hibernate.entity.CompteEpargne"
20. discriminatorvalue="CompteEpargne">
21. <propertyname="taux"column="taux"type="big_decimal"/>
22. </subclass>
23. </class>
24. </hibernatemapping>

https://www.jmdoudoux.fr/java/dej/chaphibernate.htm 50/105
24/04/2017 DvelopponsenJavaHibernate

Lorsque le type d'entit demand Hibernate est prcisment identifi, il peut faire une requte qui ne rcupre que les colonnes ncessaires
l'alimentation des proprits de la classe.

Lorsque le type d'entit demand Hibernate est un supertype, celui-ci ne peut pas dterminer l'avance les donnes ncessaires donc il doit obtenir
toutes les donnes. A partir du discriminant, Hibernate peut crer la bonne instance et alimenter ses proprits.

Rsultat :

01. 2015022323:18:53.650INFO[main]:org.hibernate.annotations.common.VersionHCANN000001:
02. HibernateCommonsAnnotations{4.0.1.Final}
03. 2015022323:18:53.663INFO[main]:org.hibernate.VersionHHH000412:HibernateCore{4.1.
04. 4.Final}
05. 2015022323:18:53.665INFO[main]:org.hibernate.cfg.EnvironmentHHH000206:hibernate.
06. propertiesnotfound
07. 2015022323:18:53.666INFO[main]:org.hibernate.cfg.EnvironmentHHH000021:Bytecode
08. providername:javassist
09. 2015022323:18:53.700INFO[main]:org.hibernate.cfg.ConfigurationHHH000043:
10. Configuringfromresource:/hibernate.cfg.xml
11. 2015022323:18:53.700INFO[main]:org.hibernate.cfg.ConfigurationHHH000040:
12. Configurationresource:/hibernate.cfg.xml
13. 2015022323:18:53.753INFO[main]:org.hibernate.cfg.ConfigurationHHH000221:Reading
14. mappingsfromresource:Compte.hbm.xml
15. 2015022323:18:53.823INFO[main]:org.hibernate.cfg.ConfigurationHHH000041:Configured
16. SessionFactory:null
17. 2015022323:18:53.926INFO[main]:org.hibernate.service.jdbc.connections.internal.
18. DriverManagerConnectionProviderImplHHH000402:UsingHibernatebuiltinconnectionpool(not
19. forproductionuse!)
20. 2015022323:18:53.941INFO[main]:org.hibernate.service.jdbc.connections.internal.
21. DriverManagerConnectionProviderImplHHH000115:Hibernateconnectionpoolsize:1
22. 2015022323:18:53.941INFO[main]:org.hibernate.service.jdbc.connections.internal.
23. DriverManagerConnectionProviderImplHHH000006:Autocommitmode:false
24. 2015022323:18:53.942INFO[main]:org.hibernate.service.jdbc.connections.internal.
25. DriverManagerConnectionProviderImplHHH000401:usingdriver[com.mysql.jdbc.Driver]atURL[
26. jdbc:mysql://localhost:3307/mabdd]
27. 2015022323:18:53.942INFO[main]:org.hibernate.service.jdbc.connections.internal.
28. DriverManagerConnectionProviderImplHHH000046:Connectionproperties:{user=root,password=
29. ****}
30. 2015022323:18:54.340INFO[main]:org.hibernate.dialect.DialectHHH000400:Using
31. dialect:org.hibernate.dialect.MySQL5Dialect
32. 2015022323:18:54.361INFO[main]:org.hibernate.engine.transaction.internal.
33. TransactionFactoryInitiatorHHH000399:Usingdefaulttransactionstrategy(directJDBC
34. transactions)
35. 2015022323:18:54.366INFO[main]:org.hibernate.hql.internal.ast.
36. ASTQueryTranslatorFactoryHHH000397:UsingASTQueryTranslatorFactory
37. 2015022323:18:54.617INFO[main]:org.hibernate.tool.hbm2ddl.SchemaExportHHH000227:
38. Runninghbm2ddlschemaexport
39. Hibernate:droptableifexistscompte
40. Hibernate:createtablecompte(idintegernotnullauto_increment,DTYPEvarchar(255)not
41. null,numerovarchar(255),soldedecimal(19,2),decouvertinteger,tauxdecimal(19,2),primary
42. key(id))
43. 2015022323:18:54.707INFO[main]:org.hibernate.tool.hbm2ddl.SchemaExportHHH000230:
44. Schemaexportcomplete
45. Hibernate:insertintocompte(numero,solde,DTYPE)values(?,?,'Compte')
46. Hibernate:insertintocompte(numero,solde,decouvert,DTYPE)values(?,?,?,'
47. CompteCourant')
48. Hibernate:insertintocompte(numero,solde,taux,DTYPE)values(?,?,?,'CompteEpargne')
49. Recherched'uncompte
50. Hibernate:selectcompte0_.idasid0_0_,compte0_.numeroasnumero0_0_,compte0_.soldeas
51. solde0_0_,compte0_.decouvertasdecouvert0_0_,compte0_.tauxastaux0_0_,compte0_.DTYPEas
52. DTYPE0_0_fromcomptecompte0_wherecompte0_.id=?
53. com.jmdoudoux.test.hibernate.entity.Compte@3c3daf[id=1,numero=000012345000,solde=0.00]
54.
55. Recherched'uncomptecourant
56. Hibernate:selectcomptecour0_.idasid0_0_,comptecour0_.numeroasnumero0_0_,comptecour0_.
57. soldeassolde0_0_,comptecour0_.decouvertasdecouvert0_0_fromcomptecomptecour0_where
58. comptecour0_.id=?andcomptecour0_.DTYPE='CompteCourant'
59. com.jmdoudoux.test.hibernate.entity.CompteCourant@26380823CompteCourant[id=2,numero=
60. 000012345010,solde=1200.00,decouvert=2000]
61.
62. Recherchepolymorphiqued'uncompte
63. Hibernate:selectcompte0_.idasid0_0_,compte0_.numeroasnumero0_0_,compte0_.soldeas
64. solde0_0_,compte0_.decouvertasdecouvert0_0_,compte0_.tauxastaux0_0_,compte0_.DTYPEas
65. DTYPE0_0_fromcomptecompte0_wherecompte0_.id=?
66. com.jmdoudoux.test.hibernate.entity.CompteEpargne@641293CompteEpargne[id=3,numero=
67. 000012345020,solde=8000.00,taux=2.10]
68.
69. Recherchedetouslescomptes
70. Hibernate:selectcompte0_.idasid0_,compte0_.numeroasnumero0_,compte0_.soldeassolde0_,
71. compte0_.decouvertasdecouvert0_,compte0_.tauxastaux0_,compte0_.DTYPEasDTYPE0_from
72. comptecompte0_
73. com.jmdoudoux.test.hibernate.entity.Compte@1c458a5[id=1,numero=000012345000,solde=0.00]
74. com.jmdoudoux.test.hibernate.entity.CompteCourant@953079CompteCourant[id=2,numero=
75. 000012345010,solde=1200.00,decouvert=2000]
76. com.jmdoudoux.test.hibernate.entity.CompteEpargne@12941261CompteEpargne[id=3,numero=
77. 000012345020,solde=8000.00,taux=2.10]
78.
79. Recherchepolymorphiquedecomptes
80. Hibernate:selectcompte0_.idasid0_,compte0_.numeroasnumero0_,compte0_.soldeassolde0_,
81. compte0_.decouvertasdecouvert0_,compte0_.tauxastaux0_,compte0_.DTYPEasDTYPE0_from
82. comptecompte0_wherecompte0_.numerolike?
83. com.jmdoudoux.test.hibernate.entity.Compte@4cb73c[id=1,numero=000012345000,solde=0.00]
84. com.jmdoudoux.test.hibernate.entity.CompteCourant@9557173CompteCourant[id=2,numero=
85. 000012345010,solde=1200.00,decouvert=2000]
https://www.jmdoudoux.fr/java/dej/chaphibernate.htm 51/105
24/04/2017 DvelopponsenJavaHibernate
85. 000012345010,solde=1200.00,decouvert=2000]
86. com.jmdoudoux.test.hibernate.entity.CompteEpargne@975425CompteEpargne[id=3,numero=
87. 000012345020,solde=8000.00,taux=2.10]

Rsultat :

01. mysql>select*fromcompte;
02. +++++++
03. |id|DTYPE|numero|solde|decouvert|taux|
04. +++++++
05. |1|Compte|000012345000|0.00|NULL|NULL|
06. |2|CompteCourant|000012345010|1200.00|2000|NULL|
07. |3|CompteEpargne|000012345020|8000.00|NULL|2.10|
08. +++++++
09. 3rowsinset(0.00sec)

54.11.1.2. XML, une table par sous-classe

Le modle relationnel et le modle objet correspondant sont trs proches: une table est utilise pour chaque classe de la hirarchie.

Les donnes d'une classe fille sont rparties dans la table de la classe mre pour les donnes hrites et dans la table de la classe fille pour ses
donnes spcifiques. Cette stratgie ne require pas de colonne de type discriminant.

La dfinition du mapping de la classe mre et de la classe fille se fait dans le mme fichier .hbm. Pour dfinir le mapping d'un hritage utilisant le
modle une table par sous-classe, il faut utiliserdans un mme fichier hbm :

un tag <class> pour le mapping classe mre


un tag <joined-subclass> pour le mapping de chaque classe fille

Le tag <joined-subclass> possde plusieurs attributs:

Nom Rle

entity-name Par dfaut, le nom de la classe

name Nom pleinement qualifi de la classe de l'entit

proxy Nom de la classe ou de l'interface utilise pour crer des proxys lors des lectures lazy. Optionnel

table Nom de la table. par dfaut le nom de la classe

schema Nom du schma qui contiendra la table

catalog Nom du catalogue qui contiendra la table

subselect Requte SQL qui sera excute pour obtenir les donnes immuables de l'entit

dynamic-update true ou false (par dfaut)

dynamic-insert true ou false (par dfaut)

select-before-update true ou false (par dfaut)

extends Nom de la superclasse pour une entit fille. Optionnel

lazy Activation du lazy fetching: true ou false. Optionnel: par dfaut true

abstract true ou false: prciser si la classe est abstraite

persister Nom de la classe de type ClassPersister utiliser

check Optionnel

batch-size Prciser le nombre d'occurrences obtenues lors de la lecture par lots. Optionnel

node

https://www.jmdoudoux.fr/java/dej/chaphibernate.htm 52/105
24/04/2017 DvelopponsenJavaHibernate

Lors de l'utilisation de cette stratgie, la superclasse a une table et chaque sous-classe a une table qui contient seulement ses proprits non-hrites :
les tables des classes filles ont une cl primaire est une cl trangre vers la table de la superclasse. Hibernate va utiliser une relation de type 1-1
entre la cl primaire de la table mre et la cl trangre de la table fille. Ceci implique une jointure entre les deux tables pour obtenir les donnes.

Le tag <id> du tag <class> permet de prciser la colonne qui est la cl primaire.

Le tag <key> fils du tag <joined-subclass> permet de prciser la cl trangre qui sera utilise pour raliser la jointure avec la table mre sur sa cl
primaire.

Exemple :

01. <?xmlversion="1.0"encoding="UTF8"?>
02. <!DOCTYPEhibernatemappingPUBLIC"//Hibernate/HibernateMappingDTD//EN"
03. "http://www.hibernate.org/dtd/hibernatemapping3.0.dtd">
04.
05. <hibernatemapping>
06. <classname="com.jmdoudoux.test.hibernate.entity.Compte"table="compte">
07. <idname="id"column="id"type="int">
08. <generatorclass="native"/>
09. </id>
10. <propertyname="numero"column="numero"type="string"/>
11. <propertyname="solde"column="solde"type="big_decimal"/>
12. <joinedsubclassname="com.jmdoudoux.test.hibernate.entity.CompteCourant"
13. table="compte_courant">
14. <keycolumn="id"/>
15. <propertyname="decouvert"column="decouvert"type="int"/>
16. </joinedsubclass>
17. <joinedsubclassname="com.jmdoudoux.test.hibernate.entity.CompteEpargne"
18. table="compte_epargne">
19. <keycolumn="id"/>
20. <propertyname="taux"column="taux"type="big_decimal"/>
21. </joinedsubclass>
22. </class>
23. </hibernatemapping>

Pour obtenir une occurrence de l'entit, Hibernate va automatiquement effectuer une jointure entre la table mre et la table de la classe
correspondante.

Si la requte demande Hibernate concerne le type d'une classe abstraite, Hibernate rcupre de la base de donnes toutes les donnes des
occurrences relatives toutes les classes concrtes en effectuant une jointure sur toutes les tables. Hibernate est oblig de faire une jointure sur
toutes les tables : il cre alors une instance de l'entit. Cependant, dans ce cas toutes les autres colonnes des autres tables sont lues.

Si la requte demande Hibernate concerne le type d'une classe concrte, Hibernate effectue une jointure entre la table de la classe mre et la table
de la classe fille correspondante.

Lors de l'enregistrement d'une nouvelle classe dans la base de donnes, Hibernate sa crer une nouvelle occurrence dans la table de la classe mre puis
dans la table de la classe fille. La cl de la classe mre sera utilise comme valeur dans la cl trangre de la classe fille pour permettre Hibernate de
faire la jointure lors de la lecture des donnes.

Rsultat :

001. 2015021122:34:44.154INFO[main]:org.hibernate.annotations.common.VersionHCANN000001:
002. HibernateCommonsAnnotations{4.0.1.Final}
003. 2015021122:34:44.172INFO[main]:org.hibernate.VersionHHH000412:HibernateCore{4.1.
004. 4.Final}
005. 2015021122:34:44.174INFO[main]:org.hibernate.cfg.EnvironmentHHH000206:hibernate.
006. propertiesnotfound
007. 2015021122:34:44.175INFO[main]:org.hibernate.cfg.EnvironmentHHH000021:Bytecode
008. providername:javassist
009. 2015021122:34:44.211INFO[main]:org.hibernate.cfg.ConfigurationHHH000043:
010. Configuringfromresource:/hibernate.cfg.xml
011. 2015021122:34:44.211INFO[main]:org.hibernate.cfg.ConfigurationHHH000040:
012. Configurationresource:/hibernate.cfg.xml
013. 2015021122:34:44.297INFO[main]:org.hibernate.cfg.ConfigurationHHH000221:Reading
014. mappingsfromresource:Compte.hbm.xml
015. 2015021122:34:44.366INFO[main]:org.hibernate.cfg.ConfigurationHHH000041:Configured
016. SessionFactory:null
017. 2015021122:34:44.475INFO[main]:org.hibernate.service.jdbc.connections.internal.
018. DriverManagerConnectionProviderImplHHH000402:UsingHibernatebuiltinconnectionpool(not
019. forproductionuse!)
020. 2015021122:34:44.482INFO[main]:org.hibernate.service.jdbc.connections.internal.
021. DriverManagerConnectionProviderImplHHH000115:Hibernateconnectionpoolsize:1
022. 2015021122:34:44.483INFO[main]:org.hibernate.service.jdbc.connections.internal.
023. DriverManagerConnectionProviderImplHHH000006:Autocommitmode:false
024. 2015021122:34:44.483INFO[main]:org.hibernate.service.jdbc.connections.internal.
025. DriverManagerConnectionProviderImplHHH000401:usingdriver[com.mysql.jdbc.Driver]atURL[
026. jdbc:mysql://localhost:3307/mabdd]
027. 2015021122:34:44.485INFO[main]:org.hibernate.service.jdbc.connections.internal.
028. DriverManagerConnectionProviderImplHHH000046:Connectionproperties:{user=root,password=
029. ****}
030. 2015021122:34:44.842INFO[main]:org.hibernate.dialect.DialectHHH000400:Using
031. dialect:org.hibernate.dialect.MySQL5Dialect
032. 2015021122:34:44.870INFO[main]:org.hibernate.engine.transaction.internal.
033. TransactionFactoryInitiatorHHH000399:Usingdefaulttransactionstrategy(directJDBC
034. transactions)
035. 2015021122:34:44.874INFO[main]:org.hibernate.hql.internal.ast.
036. ASTQueryTranslatorFactoryHHH000397:UsingASTQueryTranslatorFactory
https://www.jmdoudoux.fr/java/dej/chaphibernate.htm 53/105
24/04/2017 DvelopponsenJavaHibernate
036. ASTQueryTranslatorFactoryHHH000397:UsingASTQueryTranslatorFactory
037. 2015021122:34:45.100INFO[main]:org.hibernate.tool.hbm2ddl.SchemaExportHHH000227:
038. Runninghbm2ddlschemaexport
039. Hibernate:altertablecompte_courantdropforeignkeyFK2435FDBF9CCD1BB4
040. 2015021122:34:45.106ERROR[main]:org.hibernate.tool.hbm2ddl.SchemaExportHHH000389:
041. Unsuccessful:altertablecompte_courantdropforeignkeyFK2435FDBF9CCD1BB4
042. 2015021122:34:45.106ERROR[main]:org.hibernate.tool.hbm2ddl.SchemaExportTable'mabdd.
043. compte_courant'doesn'texist
044. Hibernate:altertablecompte_epargnedropforeignkeyFK8E9D8D439CCD1BB4
045. 2015021122:34:45.107ERROR[main]:org.hibernate.tool.hbm2ddl.SchemaExportHHH000389:
046. Unsuccessful:altertablecompte_epargnedropforeignkeyFK8E9D8D439CCD1BB4
047. 2015021122:34:45.107ERROR[main]:org.hibernate.tool.hbm2ddl.SchemaExportTable'mabdd.
048. compte_epargne'doesn'texist
049. Hibernate:droptableifexistscompte
050. Hibernate:droptableifexistscompte_courant
051. Hibernate:droptableifexistscompte_epargne
052. Hibernate:createtablecompte(idintegernotnullauto_increment,numerovarchar(255),solde
053. decimal(19,2),primarykey(id))
054. Hibernate:createtablecompte_courant(idintegernotnull,decouvertinteger,primarykey(
055. id))
056. Hibernate:createtablecompte_epargne(idintegernotnull,tauxdecimal(19,2),primarykey(
057. id))
058. Hibernate:altertablecompte_courantaddindexFK2435FDBF9CCD1BB4(id),addconstraint
059. FK2435FDBF9CCD1BB4foreignkey(id)referencescompte(id)
060. Hibernate:altertablecompte_epargneaddindexFK8E9D8D439CCD1BB4(id),addconstraint
061. FK8E9D8D439CCD1BB4foreignkey(id)referencescompte(id)
062. 2015021122:34:45.189INFO[main]:org.hibernate.tool.hbm2ddl.SchemaExportHHH000230:
063. Schemaexportcomplete
064. Hibernate:insertintocompte(numero,solde)values(?,?)
065. Hibernate:insertintocompte(numero,solde)values(?,?)
066. Hibernate:insertintocompte_courant(decouvert,id)values(?,?)
067. Hibernate:insertintocompte(numero,solde)values(?,?)
068. Hibernate:insertintocompte_epargne(taux,id)values(?,?)
069. Recherched'uncompte
070. Hibernate:selectcompte0_.idasid0_0_,compte0_.numeroasnumero0_0_,compte0_.soldeas
071. solde0_0_,compte0_1_.decouvertasdecouvert1_0_,compte0_2_.tauxastaux2_0_,casewhen
072. compte0_1_.idisnotnullthen1whencompte0_2_.idisnotnullthen2whencompte0_.idisnot
073. nullthen0endasclazz_0_fromcomptecompte0_leftouterjoincompte_courantcompte0_1_on
074. compte0_.id=compte0_1_.idleftouterjoincompte_epargnecompte0_2_oncompte0_.id=compte0_2_.
075. idwherecompte0_.id=?
076. com.jmdoudoux.test.hibernate.entity.Compte@e2ecb3[id=1,numero=000012345000,solde=0.00]
077.
078. Recherched'uncomptecourant
079. Hibernate:selectcomptecour0_.idasid0_0_,comptecour0_1_.numeroasnumero0_0_,
080. comptecour0_1_.soldeassolde0_0_,comptecour0_.decouvertasdecouvert1_0_fromcompte_courant
081. comptecour0_innerjoincomptecomptecour0_1_oncomptecour0_.id=comptecour0_1_.idwhere
082. comptecour0_.id=?
083. com.jmdoudoux.test.hibernate.entity.CompteCourant@1972965CompteCourant[id=2,numero=
084. 000012345010,solde=1200.00,decouvert=2000]
085.
086. Recherchepolymorphiqued'uncompte
087. Hibernate:selectcompte0_.idasid0_0_,compte0_.numeroasnumero0_0_,compte0_.soldeas
088. solde0_0_,compte0_1_.decouvertasdecouvert1_0_,compte0_2_.tauxastaux2_0_,casewhen
089. compte0_1_.idisnotnullthen1whencompte0_2_.idisnotnullthen2whencompte0_.idisnot
090. nullthen0endasclazz_0_fromcomptecompte0_leftouterjoincompte_courantcompte0_1_on
091. compte0_.id=compte0_1_.idleftouterjoincompte_epargnecompte0_2_oncompte0_.id=compte0_2_.
092. idwherecompte0_.id=?
093. com.jmdoudoux.test.hibernate.entity.CompteEpargne@32800355CompteEpargne[id=3,numero=
094. 000012345020,solde=8000.00,taux=2.10]
095.
096. Recherchedetouslescomptes
097. Hibernate:selectcompte0_.idasid0_,compte0_.numeroasnumero0_,compte0_.soldeassolde0_,
098. compte0_1_.decouvertasdecouvert1_,compte0_2_.tauxastaux2_,casewhencompte0_1_.idisnot
099. nullthen1whencompte0_2_.idisnotnullthen2whencompte0_.idisnotnullthen0endas
100. clazz_fromcomptecompte0_leftouterjoincompte_courantcompte0_1_oncompte0_.id=
101. compte0_1_.idleftouterjoincompte_epargnecompte0_2_oncompte0_.id=compte0_2_.id
102. com.jmdoudoux.test.hibernate.entity.CompteCourant@2473102CompteCourant[id=2,numero=
103. 000012345010,solde=1200.00,decouvert=2000]
104. com.jmdoudoux.test.hibernate.entity.CompteEpargne@21374993CompteEpargne[id=3,numero=
105. 000012345020,solde=8000.00,taux=2.10]
106. com.jmdoudoux.test.hibernate.entity.Compte@f08a49[id=1,numero=000012345000,solde=0.00]
107.
108. Recherchepolymorphiquedecomptes
109. Hibernate:selectcompte0_.idasid0_,compte0_.numeroasnumero0_,compte0_.soldeassolde0_,
110. compte0_1_.decouvertasdecouvert1_,compte0_2_.tauxastaux2_,casewhencompte0_1_.idisnot
111. nullthen1whencompte0_2_.idisnotnullthen2whencompte0_.idisnotnullthen0endas
112. clazz_fromcomptecompte0_leftouterjoincompte_courantcompte0_1_oncompte0_.id=
113. compte0_1_.idleftouterjoincompte_epargnecompte0_2_oncompte0_.id=compte0_2_.idwhere
114. compte0_.numerolike?
115. com.jmdoudoux.test.hibernate.entity.CompteCourant@5917204CompteCourant[id=2,numero=
116. 000012345010,solde=1200.00,decouvert=2000]
117. com.jmdoudoux.test.hibernate.entity.CompteEpargne@28671960CompteEpargne[id=3,numero=
118. 000012345020,solde=8000.00,taux=2.10]
119. com.jmdoudoux.test.hibernate.entity.Compte@ad3eb5[id=1,numero=000012345000,solde=0.00]

https://www.jmdoudoux.fr/java/dej/chaphibernate.htm 54/105
24/04/2017 DvelopponsenJavaHibernate

Rsultat :

01. mysql>select*fromcompte;
02. ++++
03. |id|numero|solde|
04. ++++
05. |1|000012345000|0.00|
06. |2|000012345010|1200.00|
07. |3|000012345020|8000.00|
08. ++++
09. 3rowsinset(0.00sec)
10. mysql>select*fromcompte_courant;
11. +++
12. |id|decouvert|
13. +++
14. |2|2000|
15. +++
16. 1rowinset(0.00sec)
17. mysql>select*fromcompte_epargne;
18. +++
19. |id|taux|
20. +++
21. |3|2.10|
22. +++
23. 1rowinset(0.00sec)

Remarque: l'identifiant de l'occurrence de la table de la classe mre et celui de l'occurrence de la table de la classe fille doivent tre identiques pour
permettre de raliser la jointure.

54.11.1.3. XML, une table par classe concrte

Dans cette stratgie, chaque classe concrte est mappe sur une table dans la base de donnes. Toutes les proprits de la classe sont partages par
les classes filles: ceci implique une duplication de ces champs dans les tables des classes filles.

La classe mre est dfinie grce un tag <class>.

Chaque classe fille est dfinie grce un tag fils <union-subclass>. Il possde plusieurs attributs:

name: nom pleinement qualifi de la classe


table: nom de la table dans la base de donnes

Les colonnes de la table de la classe mre sont aussi prsentes dans les tables des classes filles. Chaque proprit propre une classe fille doit tre
mappe dans le tag <union-subclass> correspondant.

Le tag <union-subclass> possde plusieurs attributs:

Attribut Rle

entity-name Par dfaut, le nom de la classe

name Nom pleinement qualifi de la classe

proxy Interface ou classe qui est utilise pour la cration des proxys. Optionnel

table Nom de la table. Par dfaut : le nom de la classe

schema Nom du schma qui contiendra la table

catalog Nom du catalogue qui contiendra la table

subselect Requte SQL qui sera excute pour obtenir les donnes immuables de l'entit

dynamic-update true ou false (par dfaut)

dynamic-insert true ou false (par dfaut)

https://www.jmdoudoux.fr/java/dej/chaphibernate.htm 55/105
24/04/2017 DvelopponsenJavaHibernate
select-before-update true ou false (par dfaut)

extends Nom de la super classe pour une entit fille. Optionnel

lazy true ou false

abstract true ou false

persister Prciser un ClassPersister personnalis. Optionnel

check Optionnel

batch-size Dfinir le nombre d'occurrences rcupres par lot. Optionnel

node

Le champ identifiant de la classe mre est partag avec les classes filles: ce champ n'est d'ailleurs pas mapp dans les classes filles.

Remarque: il n'est pas possible d'utiliser la stratgie de gestion native des identifiants.

Exemple :

01. <?xmlversion="1.0"encoding="UTF8"?>
02. <!DOCTYPEhibernatemappingPUBLIC"//Hibernate/HibernateMappingDTD//EN"
03. "http://www.hibernate.org/dtd/hibernatemapping3.0.dtd">
04.
05. <hibernatemapping>
06. <classname="com.jmdoudoux.test.hibernate.entity.Compte"
07. table="compte">
08. <idname="id"column="id"type="int">
09. <generatorclass="increment"/>
10. </id>
11. <propertyname="numero"column="numero"type="string"/>
12. <propertyname="solde"column="solde"type="big_decimal"/>
13. <unionsubclassname="com.jmdoudoux.test.hibernate.entity.CompteCourant"
14. table="compte_courant">
15. <propertyname="decouvert"column="decouvert"type="int"/>
16. </unionsubclass>
17. <unionsubclassname="com.jmdoudoux.test.hibernate.entity.CompteEpargne"
18. table="compte_epargne">
19. <propertyname="taux"column="taux"type="big_decimal"/>
20. </unionsubclass>
21. </class>
22. </hibernatemapping>

Rsultat :

001. 2015021122:37:45.178INFO[main]:org.hibernate.annotations.common.VersionHCANN000001:
002. HibernateCommonsAnnotations{4.0.1.Final}
003. 2015021122:37:45.194INFO[main]:org.hibernate.VersionHHH000412:HibernateCore{4.1.
004. 4.Final}
005. 2015021122:37:45.194INFO[main]:org.hibernate.cfg.EnvironmentHHH000206:hibernate.
006. propertiesnotfound
007. 2015021122:37:45.194INFO[main]:org.hibernate.cfg.EnvironmentHHH000021:Bytecode
008. providername:javassist
009. 2015021122:37:45.225INFO[main]:org.hibernate.cfg.ConfigurationHHH000043:
010. Configuringfromresource:/hibernate.cfg.xml
011. 2015021122:37:45.225INFO[main]:org.hibernate.cfg.ConfigurationHHH000040:
012. Configurationresource:/hibernate.cfg.xml
013. 2015021122:37:45.272INFO[main]:org.hibernate.cfg.ConfigurationHHH000221:Reading
014. mappingsfromresource:Compte.hbm.xml
015. 2015021122:37:45.319INFO[main]:org.hibernate.cfg.ConfigurationHHH000041:Configured
016. SessionFactory:null
017. 2015021122:37:45.443INFO[main]:org.hibernate.service.jdbc.connections.internal.
018. DriverManagerConnectionProviderImplHHH000402:UsingHibernatebuiltinconnectionpool(not
019. forproductionuse!)
020. 2015021122:37:45.443INFO[main]:org.hibernate.service.jdbc.connections.internal.
021. DriverManagerConnectionProviderImplHHH000115:Hibernateconnectionpoolsize:1
022. 2015021122:37:45.443INFO[main]:org.hibernate.service.jdbc.connections.internal.
023. DriverManagerConnectionProviderImplHHH000006:Autocommitmode:false
024. 2015021122:37:45.443INFO[main]:org.hibernate.service.jdbc.connections.internal.
025. DriverManagerConnectionProviderImplHHH000401:usingdriver[com.mysql.jdbc.Driver]atURL[
026. jdbc:mysql://localhost:3307/mabdd]
027. 2015021122:37:45.459INFO[main]:org.hibernate.service.jdbc.connections.internal.
028. DriverManagerConnectionProviderImplHHH000046:Connectionproperties:{user=root,password=
029. ****}
030. 2015021122:37:45.787INFO[main]:org.hibernate.dialect.DialectHHH000400:Using
031. dialect:org.hibernate.dialect.MySQL5Dialect
032. 2015021122:37:45.803INFO[main]:org.hibernate.engine.transaction.internal.
033. TransactionFactoryInitiatorHHH000399:Usingdefaulttransactionstrategy(directJDBC
034. transactions)
035. 2015021122:37:45.803INFO[main]:org.hibernate.hql.internal.ast.
036. ASTQueryTranslatorFactoryHHH000397:UsingASTQueryTranslatorFactory
037. 2015021122:37:46.014INFO[main]:org.hibernate.tool.hbm2ddl.SchemaExportHHH000227:
038. Runninghbm2ddlschemaexport
039. Hibernate:droptableifexistscompte
040. Hibernate:droptableifexistscompte_courant
041. Hibernate:droptableifexistscompte_epargne
042. Hibernate:createtablecompte(idintegernotnull,numerovarchar(255),soldedecimal(19,2),
043. primarykey(id))
044. Hibernate:createtablecompte_courant(idintegernotnull,numerovarchar(255),solde
https://www.jmdoudoux.fr/java/dej/chaphibernate.htm 56/105
24/04/2017 DvelopponsenJavaHibernate
044. Hibernate:createtablecompte_courant(idintegernotnull,numerovarchar(255),solde
045. decimal(19,2),decouvertinteger,primarykey(id))
046. Hibernate:createtablecompte_epargne(idintegernotnull,numerovarchar(255),solde
047. decimal(19,2),tauxdecimal(19,2),primarykey(id))
048. 2015021122:37:46.046INFO[main]:org.hibernate.tool.hbm2ddl.SchemaExportHHH000230:
049. Schemaexportcomplete
050. Hibernate:selectmax(ids_.id)from(selectidfromcompte_courantunionselectidfrom
051. compteunionselectidfromcompte_epargne)ids_
052. Hibernate:insertintocompte(numero,solde,id)values(?,?,?)
053. Hibernate:insertintocompte_courant(numero,solde,decouvert,id)values(?,?,?,?)
054. Hibernate:insertintocompte_epargne(numero,solde,taux,id)values(?,?,?,?)
055. Recherched'uncompte
056. Hibernate:selectcompte0_.idasid0_0_,compte0_.numeroasnumero0_0_,compte0_.soldeas
057. solde0_0_,compte0_.decouvertasdecouvert1_0_,compte0_.tauxastaux2_0_,compte0_.clazz_as
058. clazz_0_from(selectid,numero,solde,nullasdecouvert,nullastaux,0asclazz_from
059. compteunionselectid,numero,solde,decouvert,nullastaux,1asclazz_from
060. compte_courantunionselectid,numero,solde,nullasdecouvert,taux,2asclazz_from
061. compte_epargne)compte0_wherecompte0_.id=?
062. com.jmdoudoux.test.hibernate.entity.Compte@2c5b4e[id=1,numero=000012345000,solde=0.00]
063.
064. Recherched'uncomptecourant
065. Hibernate:selectcomptecour0_.idasid0_0_,comptecour0_.numeroasnumero0_0_,comptecour0_.
066. soldeassolde0_0_,comptecour0_.decouvertasdecouvert1_0_fromcompte_courantcomptecour0_
067. wherecomptecour0_.id=?
068. com.jmdoudoux.test.hibernate.entity.CompteCourant@21999623CompteCourant[id=2,numero=
069. 000012345010,solde=1200.00,decouvert=2000]
070.
071. Recherchepolymorphiqued'uncompte
072. Hibernate:selectcompte0_.idasid0_0_,compte0_.numeroasnumero0_0_,compte0_.soldeas
073. solde0_0_,compte0_.decouvertasdecouvert1_0_,compte0_.tauxastaux2_0_,compte0_.clazz_as
074. clazz_0_from(selectid,numero,solde,nullasdecouvert,nullastaux,0asclazz_from
075. compteunionselectid,numero,solde,decouvert,nullastaux,1asclazz_from
076. compte_courantunionselectid,numero,solde,nullasdecouvert,taux,2asclazz_from
077. compte_epargne)compte0_wherecompte0_.id=?
078. com.jmdoudoux.test.hibernate.entity.CompteEpargne@7659203CompteEpargne[id=3,numero=
079. 000012345020,solde=8000.00,taux=2.10]
080.
081. Recherchedetouslescomptes
082. Hibernate:selectcompte0_.idasid0_,compte0_.numeroasnumero0_,compte0_.soldeassolde0_,
083. compte0_.decouvertasdecouvert1_,compte0_.tauxastaux2_,compte0_.clazz_asclazz_from(
084. selectid,numero,solde,nullasdecouvert,nullastaux,0asclazz_fromcompteunion
085. selectid,numero,solde,decouvert,nullastaux,1asclazz_fromcompte_courantunion
086. selectid,numero,solde,nullasdecouvert,taux,2asclazz_fromcompte_epargne)compte0_
087. com.jmdoudoux.test.hibernate.entity.Compte@12a81c9[id=1,numero=000012345000,solde=0.00]
088. com.jmdoudoux.test.hibernate.entity.CompteCourant@24930042CompteCourant[id=2,numero=
089. 000012345010,solde=1200.00,decouvert=2000]
090. com.jmdoudoux.test.hibernate.entity.CompteEpargne@5027644CompteEpargne[id=3,numero=
091. 000012345020,solde=8000.00,taux=2.10]
092.
093. Recherchepolymorphiquedecomptes
094. Hibernate:selectcompte0_.idasid0_,compte0_.numeroasnumero0_,compte0_.soldeassolde0_,
095. compte0_.decouvertasdecouvert1_,compte0_.tauxastaux2_,compte0_.clazz_asclazz_from(
096. selectid,numero,solde,nullasdecouvert,nullastaux,0asclazz_fromcompteunion
097. selectid,numero,solde,decouvert,nullastaux,1asclazz_fromcompte_courantunion
098. selectid,numero,solde,nullasdecouvert,taux,2asclazz_fromcompte_epargne)compte0_
099. wherecompte0_.numerolike?
100. com.jmdoudoux.test.hibernate.entity.Compte@1a93ff1[id=1,numero=000012345000,solde=0.00]
101. com.jmdoudoux.test.hibernate.entity.CompteCourant@10814140CompteCourant[id=2,numero=
102. 000012345010,solde=1200.00,decouvert=2000]
103. com.jmdoudoux.test.hibernate.entity.CompteEpargne@12935409CompteEpargne[id=3,numero=
104. 000012345020,solde=8000.00,taux=2.10]

Rsultat :

01. mysql>select*fromcompte;
02. ++++
03. |id|numero|solde|
04. ++++
05. |1|000012345000|0.00|
06. |2|000012345010|1200.00|
07. |3|000012345020|8000.00|
08. |4|000012345000|0.00|
09. ++++
10. 4rowsinset(0.00sec)
11. mysql>select*fromcompte_courant;
12. +++++
13. |id|numero|solde|decouvert|
14. +++++
15. |5|000012345010|1200.00|2000|
16. +++++

17. 1rowinset(0.00sec)
https://www.jmdoudoux.fr/java/dej/chaphibernate.htm 57/105
24/04/2017 DvelopponsenJavaHibernate
17. 1rowinset(0.00sec)
18. mysql>select*fromcompte_epargne;
19. +++++
20. |id|numero|solde|taux|
21. +++++
22. |6|000012345020|8000.00|2.10|
23. +++++
24. 1rowinset(0.00sec)

Il est important que deux tables de classes filles d'une mme hirarchie ne possdent pas le mme identifiant. Hibernate pourrait alors renvoyer
plusieurs objets pour un mme identifiant en effectuant une union sur les diffrentes tables. C'est la raison pour laquelle il n'est pas possible d'utiliser
la stratgie native pour la gnration des identifiants.

Exemple :

1. <idname="id"column="id"type="int">
2. <generatorclass="native"/>
3. </id>

Rsultat :

01. org.hibernate.MappingException:Cannotuseidentitycolumnkeygenerationwith<unionsubclass>
02. mappingfor:com.jmdoudoux.test.hibernate.entity.CompteEpargne
03. atorg.hibernate.persister.entity.UnionSubclassEntityPersister.<init>(
04. UnionSubclassEntityPersister.java:93)
05. atsun.reflect.NativeConstructorAccessorImpl.newInstance0(NativeMethod)
06. atsun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:
07. 57)
08. atsun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImp
09. l.java:45)
10. atjava.lang.reflect.Constructor.newInstance(Constructor.java:525)
11. atorg.hibernate.persister.internal.PersisterFactoryImpl.create(PersisterFactoryImpl.java:
12. 163)
13. atorg.hibernate.persister.internal.PersisterFactoryImpl.createEntityPersister(
14. PersisterFactoryImpl.java:135)
15. atorg.hibernate.internal.SessionFactoryImpl.<init>(SessionFactoryImpl.java:386)
16. atorg.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:1744)
17. atcom.jmdoudoux.test.hibernate.TestHibernate.main(TestHibernate.java:27)
18. Exceptioninthread"main"java.lang.NullPointerException
19. atcom.jmdoudoux.test.hibernate.TestHibernate.main(TestHibernate.java:54)

54.11.1.4. XML, une table par sous-classe avec discriminant

La mise en oeuvre de cette stratgie requiert la dfinition d'un champ qui sera le discriminant dans la classe mre.

Chaque classe fille est mappe en utilisant un tag <subclass> avec deux proprits:

name: prcise le nom pleinement qualifi de la classe


discriminator_value: prcise la valeur qui sera utilise dans la colonne discriminator

Il faut lui ajouter un tag fils <join> pour dfinir le mapping de la table avec plusieurs proprits:

table permet de prciser le nom de la table.


fetch permet de prciser la stratgie utilise pour rcuprer les donnes. La valeur select permet de demander Hibernate de ne pas faire de
jointure externe sur la table lors d'une lecture sur la classe mre

Le tag fils <key> permet de prciser le champ qui sera la cl de la table. Il possde plusieurs attributs:

Nom Rle

column Le nom de la colonne qui est la cl trangre. Optionnel

on-delete noaction ou cascade. Optionnel, par dfaut noaction

property-ref Prciser un nom de proprit pour indiquer que la cl trangre ne fait pas rfrence la cl primaire de la table mre. Optionnel

not-null Prciser si la cl trangre peut tre null: true ou false. Optionnel

update Prciser si la cl trangre doit tre mise jour: true ou false. Optionnel

unique Prciser si la cl trangre doit avoir une contrainte d'unicit: true ou false. Optionnel

Exemple :

01. <?xmlversion="1.0"encoding="UTF8"?>
02. <!DOCTYPEhibernatemappingPUBLIC"//Hibernate/HibernateMappingDTD//EN"
03. "http://www.hibernate.org/dtd/hibernatemapping3.0.dtd">
04.
https://www.jmdoudoux.fr/java/dej/chaphibernate.htm 58/105
24/04/2017 DvelopponsenJavaHibernate
04.
05. <hibernatemapping>
06. <classname="com.jmdoudoux.test.hibernate.entity.Compte"
07. table="compte"discriminatorvalue="Compte">
08. <idname="id"column="id"type="int">
09. <generatorclass="native"/>
10. </id>
11. <discriminatorcolumn="DTYPE"type="string"/>
12.
13. <propertyname="numero"column="numero"type="string"/>
14. <propertyname="solde"column="solde"type="big_decimal"/>
15. <subclassname="com.jmdoudoux.test.hibernate.entity.CompteCourant"
16. discriminatorvalue="CompteCourant">
17. <jointable="compte_courant">
18. <keycolumn="compte_courant_id"/>
19. <propertyname="decouvert"column="decouvert"type="int"/>
20. </join>
21. </subclass>
22. <subclassname="com.jmdoudoux.test.hibernate.entity.CompteEpargne"
23. discriminatorvalue="CompteEpargne">
24. <jointable="compte_epargne">
25. <keycolumn="compte_epargne_id"/>
26. <propertyname="taux"column="taux"type="big_decimal"/>
27. </join>
28. </subclass>
29. </class>
30. </hibernatemapping>

Rsultat :

01. 2015020321:59:56.856INFO[main]:org.hibernate.annotations.common.VersionHCANN000001:
02. HibernateCommonsAnnotations{4.0.1.Final}
03. 2015020321:59:56.864INFO[main]:org.hibernate.VersionHHH000412:HibernateCore{4.1.
04. 4.Final}
05. 2015020321:59:56.866INFO[main]:org.hibernate.cfg.EnvironmentHHH000206:hibernate.
06. propertiesnotfound
07. 2015020321:59:56.868INFO[main]:org.hibernate.cfg.EnvironmentHHH000021:Bytecode
08. providername:javassist
09. 2015020321:59:56.895INFO[main]:org.hibernate.cfg.ConfigurationHHH000043:
10. Configuringfromresource:/hibernate.cfg.xml
11. 2015020321:59:56.895INFO[main]:org.hibernate.cfg.ConfigurationHHH000040:
12. Configurationresource:/hibernate.cfg.xml
13. 2015020321:59:56.943INFO[main]:org.hibernate.cfg.ConfigurationHHH000221:Reading
14. mappingsfromresource:Compte.hbm.xml
15. 2015020321:59:57.000INFO[main]:org.hibernate.cfg.ConfigurationHHH000041:Configured
16. SessionFactory:null
17. 2015020321:59:57.104INFO[main]:org.hibernate.service.jdbc.connections.internal.
18. DriverManagerConnectionProviderImplHHH000402:UsingHibernatebuiltinconnectionpool(not
19. forproductionuse!)
20. 2015020321:59:57.115INFO[main]:org.hibernate.service.jdbc.connections.internal.
21. DriverManagerConnectionProviderImplHHH000115:Hibernateconnectionpoolsize:1
22. 2015020321:59:57.116INFO[main]:org.hibernate.service.jdbc.connections.internal.
23. DriverManagerConnectionProviderImplHHH000006:Autocommitmode:false
24. 2015020321:59:57.116INFO[main]:org.hibernate.service.jdbc.connections.internal.
25. DriverManagerConnectionProviderImplHHH000401:usingdriver[com.mysql.jdbc.Driver]atURL
26. [jdbc:mysql://localhost:3307/mabdd]
27. 2015020321:59:57.117INFO[main]:org.hibernate.service.jdbc.connections.internal.
28. DriverManagerConnectionProviderImplHHH000046:Connectionproperties:{user=root,password=
29. ****}
30. 2015020321:59:57.530INFO[main]:org.hibernate.dialect.DialectHHH000400:Using
31. dialect:org.hibernate.dialect.MySQL5Dialect
32. 2015020321:59:57.552INFO[main]:org.hibernate.engine.transaction.internal.
33. TransactionFactoryInitiatorHHH000399:Usingdefaulttransactionstrategy(directJDBC
34. transactions)
35. 2015020321:59:57.557INFO[main]:org.hibernate.hql.internal.ast.
36. ASTQueryTranslatorFactoryHHH000397:UsingASTQueryTranslatorFactory
37. 2015020321:59:57.897INFO[main]:org.hibernate.tool.hbm2ddl.SchemaExportHHH000227:
38. Runninghbm2ddlschemaexport
39. Hibernate:altertablecompte_courantdropforeignkeyFK2435FDBFBBF1A400
40. 2015020321:59:57.915ERROR[main]:org.hibernate.tool.hbm2ddl.SchemaExportHHH000389:
41. Unsuccessful:altertablecompte_courantdropforeignkeyFK2435FDBFBBF1A400
42. 2015020321:59:57.915ERROR[main]:org.hibernate.tool.hbm2ddl.SchemaExportTable
43. 'mabdd.compte_courant'doesn'texist
44. Hibernate:altertablecompte_epargnedropforeignkeyFK8E9D8D438FCF4580
45. 2015020321:59:57.917ERROR[main]:org.hibernate.tool.hbm2ddl.SchemaExportHHH000389:
46. Unsuccessful:altertablecompte_epargnedropforeignkeyFK8E9D8D438FCF4580
47. 2015020321:59:57.917ERROR[main]:org.hibernate.tool.hbm2ddl.SchemaExportTable'mabdd.
48. compte_epargne'doesn'texist
49. Hibernate:droptableifexistscompte
50. Hibernate:droptableifexistscompte_courant
51. Hibernate:droptableifexistscompte_epargne
52. Hibernate:createtablecompte(idintegernotnullauto_increment,DTYPEvarchar(255)not
53. null,numerovarchar(255),soldedecimal(19,2),primarykey(id))
54. Hibernate:createtablecompte_courant(compte_courant_idintegernotnull,decouvertinteger
55. ,primarykey(compte_courant_id))
56. Hibernate:createtablecompte_epargne(compte_epargne_idintegernotnull,tauxdecimal(19,2)
57. ,primarykey(compte_epargne_id))
58. Hibernate:altertablecompte_courantaddindexFK2435FDBFBBF1A400(compte_courant_id),add
59. constraintFK2435FDBFBBF1A400foreignkey(compte_courant_id)referencescompte(id)
60. Hibernate:altertablecompte_epargneaddindexFK8E9D8D438FCF4580(compte_epargne_id),add
61. constraintFK8E9D8D438FCF4580foreignkey(compte_epargne_id)referencescompte(id)
62. 2015020321:59:58.088INFO[main]:org.hibernate.tool.hbm2ddl.SchemaExportHHH000230:
63. Schemaexportcomplete
64. Hibernate:insertintocompte(numero,solde,DTYPE)values(?,?,'Compte')
65. Hibernate:insertintocompte(numero,solde,DTYPE)values(?,?,'CompteCourant')
https://www.jmdoudoux.fr/java/dej/chaphibernate.htm 59/105
24/04/2017 DvelopponsenJavaHibernate
65. Hibernate:insertintocompte(numero,solde,DTYPE)values(?,?,'CompteCourant')
66. Hibernate:insertintocompte_courant(decouvert,compte_courant_id)values(?,?)
67. Hibernate:insertintocompte(numero,solde,DTYPE)values(?,?,'CompteEpargne')
68. Hibernate:insertintocompte_epargne(taux,compte_epargne_id)values(?,?)

Rsultat :

01. CREATETABLE`compte`(
02. `id`int(11)NOTNULLAUTO_INCREMENT,
03. `DTYPE`varchar(255)NOTNULL,
04. `numero`varchar(255)DEFAULTNULL,
05. `solde`decimal(19,2)DEFAULTNULL,
06. PRIMARYKEY(`id`)
07. )ENGINE=InnoDBAUTO_INCREMENT=4DEFAULTCHARSET=utf8;
08.
09. CREATETABLE`compte_courant`(
10. `compte_courant_id`int(11)NOTNULL,
11. `decouvert`int(11)DEFAULTNULL,
12. PRIMARYKEY(`compte_courant_id`),
13. KEY`FK2435FDBFBBF1A400`(`compte_courant_id`),
14. CONSTRAINT`FK2435FDBFBBF1A400`FOREIGNKEY(`compte_courant_id`)REFERENCES`compte`(`id`)
15. )ENGINE=InnoDBDEFAULTCHARSET=utf8;
16.
17. CREATETABLE`compte_epargne`(
18. `compte_epargne_id`int(11)NOTNULL,
19. `taux`decimal(19,2)DEFAULTNULL,
20. PRIMARYKEY(`compte_epargne_id`),
21. KEY`FK8E9D8D438FCF4580`(`compte_epargne_id`),
22. CONSTRAINT`FK8E9D8D438FCF4580`FOREIGNKEY(`compte_epargne_id`)REFERENCES`compte`(`id`)
23. )ENGINE=InnoDBDEFAULTCHARSET=utf8;

Rsultat :

01. mysql>select*fromcompte;
02. +++++
03. |id|DTYPE|numero|solde|
04. +++++
05. |1|Compte|000012345000|0.00|
06. |2|CompteCourant|000012345010|1200.00|
07. |3|CompteEpargne|000012345020|8000.00|
08. +++++
09. 3rowsinset(0.00sec)
10. mysql>select*fromcompte_courant;
11. +++
12. |compte_courant_id|decouvert|
13. +++
14. |2|2000|
15. +++
16. 1rowinset(0.00sec)
17. mysql>select*fromcompte_epargne;
18. +++
19. |compte_epargne_id|taux|
20. +++
21. |3|2.10|
22. +++
23. 1rowinset(0.00sec)

Rsultat :

01. Recherched'uncompte
02. Hibernate:selectcompte0_.idasid0_0_,compte0_.numeroasnumero0_0_,compte0_.soldeas
https://www.jmdoudoux.fr/java/dej/chaphibernate.htm 60/105
24/04/2017 DvelopponsenJavaHibernate
02. Hibernate:selectcompte0_.idasid0_0_,compte0_.numeroasnumero0_0_,compte0_.soldeas
03. solde0_0_,compte0_1_.decouvertasdecouvert1_0_,compte0_2_.tauxastaux2_0_,compte0_.DTYPE
04. asDTYPE0_0_fromcomptecompte0_leftouterjoincompte_courantcompte0_1_oncompte0_.id=
05. compte0_1_.compte_courant_idleftouterjoincompte_epargnecompte0_2_oncompte0_.id=
06. compte0_2_.compte_epargne_idwherecompte0_.id=?
07. com.jmdoudoux.test.hibernate.entity.Compte@422ddc[id=1,numero=000012345000,solde=0.00]
08.
09. Recherched'uncomptecourant
10. Hibernate:selectcomptecour0_.idasid0_0_,comptecour0_.numeroasnumero0_0_,comptecour0_.
11. soldeassolde0_0_,comptecour0_1_.decouvertasdecouvert1_0_fromcomptecomptecour0_inner
12. joincompte_courantcomptecour0_1_oncomptecour0_.id=comptecour0_1_.compte_courant_idwhere
13. comptecour0_.id=?andcomptecour0_.DTYPE='CompteCourant'
14. com.jmdoudoux.test.hibernate.entity.CompteCourant@32800355CompteCourant[id=2,numero=
15. 000012345010,solde=1200.00,decouvert=2000]
16.
17. Recherchepolymorphiqued'uncompte
18. Hibernate:selectcompte0_.idasid0_0_,compte0_.numeroasnumero0_0_,compte0_.soldeas
19. solde0_0_,compte0_1_.decouvertasdecouvert1_0_,compte0_2_.tauxastaux2_0_,compte0_.DTYPE
20. asDTYPE0_0_fromcomptecompte0_leftouterjoincompte_courantcompte0_1_oncompte0_.id=
21. compte0_1_.compte_courant_idleftouterjoincompte_epargnecompte0_2_oncompte0_.id=
22. compte0_2_.compte_epargne_idwherecompte0_.id=?
23. com.jmdoudoux.test.hibernate.entity.CompteEpargne@29827422CompteEpargne[id=3,numero=
24. 000012345020,solde=8000.00,taux=2.10]
25.
26. Recherchepolymorphiquedecomptes
27. Hibernate:selectcompte0_.idasid0_,compte0_.numeroasnumero0_,compte0_.soldeassolde0_,
28. compte0_1_.decouvertasdecouvert1_,compte0_2_.tauxastaux2_,compte0_.DTYPEasDTYPE0_from
29. comptecompte0_leftouterjoincompte_courantcompte0_1_oncompte0_.id=compte0_1_.
30. compte_courant_idleftouterjoincompte_epargnecompte0_2_oncompte0_.id=compte0_2_.
31. compte_epargne_idwherecompte0_.numerolike?
32. com.jmdoudoux.test.hibernate.entity.CompteCourant@27737342CompteCourant[id=2,numero=
33. 000012345010,solde=1200.00,decouvert=2000]
34. com.jmdoudoux.test.hibernate.entity.CompteEpargne@31801703CompteEpargne[id=3,numero=
35. 000012345020,solde=8000.00,taux=2.10]
36. com.jmdoudoux.test.hibernate.entity.Compte@28e5a7[id=1,numero=000012345000,solde=0.00]

Lors de la recherche des diffrentes entits, une seule requte SQL est excute chaque fois requrant une jointure entre au moins deux tables
voire toutes les tables. Ceci peut poser des problmes de performance notamment lorsque le nombre de tables filles est plus important.

Pour palier partiellement cette problmatique, il est possible de changer la stratgie de rcupration des donnes des tables filles en demandant
Hibernate de ne pas faire de jointure mais de faire des requtes SQL ddies. Pour cela, il faut utiliser l'attribut fetch="select" du tag <join>.

Exemple :

01. <?xmlversion="1.0"encoding="UTF8"?>
02. <!DOCTYPEhibernatemappingPUBLIC"//Hibernate/HibernateMappingDTD//EN"
03. "http://www.hibernate.org/dtd/hibernatemapping3.0.dtd">
04.
05. <hibernatemapping>
06. <classname="com.jmdoudoux.test.hibernate.entity.Compte"
07. table="compte"discriminatorvalue="Compte">
08. <idname="id"column="id"type="int">
09. <generatorclass="native"/>
10. </id>
11. <discriminatorcolumn="DTYPE"type="string"/>
12.
13. <propertyname="numero"column="numero"type="string"/>
14. <propertyname="solde"column="solde"type="big_decimal"/>
15. <subclassname="com.jmdoudoux.test.hibernate.entity.CompteCourant"
16. discriminatorvalue="CompteCourant">
17. <jointable="compte_courant"fetch="select">
18. <keycolumn="compte_courant_id"/>
19. <propertyname="decouvert"column="decouvert"type="int"/>
20. </join>
21. </subclass>
22. <subclassname="com.jmdoudoux.test.hibernate.entity.CompteEpargne"
23. discriminatorvalue="CompteEpargne">
24. <jointable="compte_epargne"<b>fetch="select"</b>>
25. <keycolumn="compte_epargne_id"/>
26. <propertyname="taux"column="taux"type="big_decimal"/>
27. </join>
28. </subclass>
29. </class>
30. </hibernatemapping>

Rsultat :

01. Recherched'uncompte
02. Hibernate:selectcompte0_.idasid0_0_,compte0_.numeroasnumero0_0_,compte0_.soldeas
03. solde0_0_,compte0_.DTYPEasDTYPE0_0_fromcomptecompte0_wherecompte0_.id=?
04. com.jmdoudoux.test.hibernate.entity.Compte@e15c54[id=1,numero=000012345000,solde=0.00]
05.
06. Recherched'uncomptecourant
07. Hibernate:selectcomptecour0_.idasid0_0_,comptecour0_.numeroasnumero0_0_,comptecour0_.
08. soldeassolde0_0_,comptecour0_1_.decouvertasdecouvert1_0_fromcomptecomptecour0_inner
09. joincompte_courantcomptecour0_1_oncomptecour0_.id=comptecour0_1_.compte_courant_idwhere
10. comptecour0_.id=?andcomptecour0_.DTYPE='CompteCourant'
11. com.jmdoudoux.test.hibernate.entity.CompteCourant@24177821CompteCourant[id=2,numero=
12. 000012345010,solde=1200.00,decouvert=2000]
13.
https://www.jmdoudoux.fr/java/dej/chaphibernate.htm 61/105
24/04/2017 DvelopponsenJavaHibernate
13.
14. Recherchepolymorphiqued'uncompte
15. Hibernate:selectcompte0_.idasid0_0_,compte0_.numeroasnumero0_0_,compte0_.soldeas
16. solde0_0_,compte0_.DTYPEasDTYPE0_0_fromcomptecompte0_wherecompte0_.id=?
17. Hibernate:selectcompte_2_.tauxastaux2_fromcompte_epargnecompte_2_wherecompte_2_.
18. compte_epargne_id=?
19. com.jmdoudoux.test.hibernate.entity.CompteEpargne@11010466CompteEpargne[id=3,numero=
20. 000012345020,solde=8000.00,taux=2.10]
21.
22. Recherchepolymorphiquedecomptes
23. Hibernate:selectcompte0_.idasid0_,compte0_.numeroasnumero0_,compte0_.soldeassolde0_,
24. compte0_.DTYPEasDTYPE0_fromcomptecompte0_wherecompte0_.numerolike?
25. Hibernate:selectcompte_1_.decouvertasdecouvert1_fromcompte_courantcompte_1_where
26. compte_1_.compte_courant_id=?
27. Hibernate:selectcompte_2_.tauxastaux2_fromcompte_epargnecompte_2_wherecompte_2_.
28. compte_epargne_id=?
29. com.jmdoudoux.test.hibernate.entity.Compte@476e01[id=1,numero=000012345000,solde=0.00]
30. com.jmdoudoux.test.hibernate.entity.CompteCourant@11305489CompteCourant[id=2,numero=
31. 000012345010,solde=1200.00,decouvert=2000]
32. com.jmdoudoux.test.hibernate.entity.CompteEpargne@15939468CompteEpargne[id=3,numero=
33. 000012345020,solde=8000.00,taux=2.10]

Ce sont des requtes SQL supplmentaires dont le nombre peut devenir important en fonction des entits retournes mais ces requtes se font sur la
cl primaire des tables filles.

54.11.2. Annotations

Comme Hibernate est une implmentation de JPA, il est possible de dfinir le mapping en utilisant des annotations.

Le fichier de configuration ci-dessous est utilis dans les exemples de cette section.

Exemple :

01. <?xmlversion='1.0'encoding='utf8'?>
02. <!DOCTYPEhibernateconfigurationSYSTEM
03. "http://www.hibernate.org/dtd/hibernateconfiguration3.0.dtd">
04. <hibernateconfiguration>
05. <sessionfactory>
06. <!Databaseconnectionsettings>
07. <propertyname="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
08. <propertyname="hibernate.connection.url">jdbc:mysql://localhost:3307/mabdd</property>
09. <propertyname="hibernate.connection.username">root</property>
10. <propertyname="hibernate.connection.password">root</property>
11. <propertyname="hibernate.connection.pool_size">1</property>
12. <propertyname="hibernate.dialect">org.hibernate.dialect.MySQL5Dialect</property>
13. <propertyname="hibernate.current_session_context_class">thread</property>
14. <!Cachedesecondniveaudsactiv>
15. <propertyname="hibernate.cache.provider_class">
16. org.hibernate.cache.internal.NoCacheProvider</property>
17. <!AfficherlesrequtesSQLexcutessurlasortiestandard>
18. <propertyname="hibernate.show_sql">true</property>
19. <propertyname="hbm2ddl.auto">create</property>
20. <mappingclass="com.jmdoudoux.test.hibernate.entity.Compte"/>
21. <mappingclass="com.jmdoudoux.test.hibernate.entity.CompteCourant"/>
22. <mappingclass="com.jmdoudoux.test.hibernate.entity.CompteEpargne"/>
23. </sessionfactory>
24. </hibernateconfiguration>

Deux classes filles qui hritent de la classe Compte sont dfinies en tant qu'entits.

Exemple ( code Java 5.0 ) :

01. packagecom.jmdoudoux.test.hibernate.entity;
02.
03. importjavax.persistence.Column;
04. importjavax.persistence.Entity;
05. importjavax.persistence.Table;
06.
07. @Entity
08. @Table(name="compte_courant")
09. publicclassCompteCourantextendsCompte{
10.
11. @Column(name="decouvert")
12. privateintdecouvert;
13.
14. publicintgetDecouvert(){
15. returndecouvert;
16. }
17.
18. publicvoidsetDecouvert(intdecouvert){
19. this.decouvert=decouvert;
20. }
21.
https://www.jmdoudoux.fr/java/dej/chaphibernate.htm 62/105
24/04/2017 DvelopponsenJavaHibernate
21.
22. @Override
23. publicStringtoString(){
24. returnthis.getClass().getName()+"@"+System.identityHashCode(this)
25. +"CompteCourant[id="+id+",numero="+numero+",solde="+solde
26. +",decouvert="+decouvert+"]";
27. }
28. }

Exemple ( code Java 5.0 ) :

01. packagecom.jmdoudoux.test.hibernate.entity;
02.
03. importjava.math.BigDecimal;
04. importjavax.persistence.Column;
05. importjavax.persistence.Entity;
06. importjavax.persistence.Table;
07.
08. @Entity
09. @Table(name="compte_epargne")
10. publicclassCompteEpargneextendsCompte{
11. @Column(name="taux")
12. privateBigDecimaltaux;
13.
14. publicBigDecimalgetTaux(){
15. returntaux;
16. }
17.
18. publicvoidsetTaux(BigDecimaltaux){
19. this.taux=taux;
20. }
21.
22. @Override
23. publicStringtoString(){
24. returnthis.getClass().getName()+"@"+System.identityHashCode(this)
25. +"CompteEpargne[id="+id+",numero="+numero+",solde="
26. +solde+",taux="+taux+"]";
27. }
28. }

54.11.2.1. Annotations, une table par hirarchie de classes (SINGLE_TABLE)

L'entit de la classe mre utilise la stratgie InheritanceType.SINGLE_TABLE grce l'annotation @Inheritance.

Exemple ( code Java 5.0 ) :

01. packagecom.jmdoudoux.test.hibernate.entity;
02.
03. importjava.math.BigDecimal;
04. importjavax.persistence.Column;
05. importjavax.persistence.Entity;
06. importjavax.persistence.GeneratedValue;
07. importjavax.persistence.GenerationType;
08. importjavax.persistence.Id;
09. importjavax.persistence.Inheritance;
10. importjavax.persistence.InheritanceType;
11. importjavax.persistence.Table;
12.
13. @Entity
14. @Table(name="compte")
15. @Inheritance(strategy=InheritanceType.SINGLE_TABLE)
16. publicclassCompte{
17.
18. @Id
19. @GeneratedValue(strategy=GenerationType.TABLE)
20. @Column(name="id")
21. protectedintid;
22.
23. @Column(name="numero")
24. protectedStringnumero;
25.
26. @Column(name="solde")
27. protectedBigDecimalsolde;
28.
29. publicintgetId(){
30. returnid;
31. }
32.
33. publicvoidsetId(intid){
34. this.id=id;
35. }
36.
37. publicStringgetNumero(){
38. returnnumero;
39. }
40.
https://www.jmdoudoux.fr/java/dej/chaphibernate.htm 63/105
24/04/2017 DvelopponsenJavaHibernate
40.
41. publicvoidsetNumero(Stringnumero){
42. this.numero=numero;
43. }
44.
45. publicBigDecimalgetSolde(){
46. returnsolde;
47. }
48.
49. publicvoidsetSolde(BigDecimalsolde){
50. this.solde=solde;
51. }
52.
53. @Override
54. publicStringtoString(){
55. returnsuper.toString()+"[id="+id+",numero="+numero+",solde="
56. +solde+"]";
57. }
58. }

Rsultat :

001. 2015030323:00:59.778INFO[main]:org.hibernate.annotations.common.VersionHCANN000001:
002. HibernateCommonsAnnotations{4.0.1.Final}
003. 2015030323:00:59.786INFO[main]:org.hibernate.VersionHHH000412:HibernateCore{4.1.
004. 4.Final}
005. 2015030323:00:59.788INFO[main]:org.hibernate.cfg.EnvironmentHHH000206:hibernate.
006. propertiesnotfound
007. 2015030323:00:59.790INFO[main]:org.hibernate.cfg.EnvironmentHHH000021:Bytecode
008. providername:javassist
009. 2015030323:00:59.818INFO[main]:org.hibernate.cfg.ConfigurationHHH000043:
010. Configuringfromresource:/hibernate.cfg.xml
011. 2015030323:00:59.818INFO[main]:org.hibernate.cfg.ConfigurationHHH000040:
012. Configurationresource:/hibernate.cfg.xml
013. 2015030323:00:59.874INFO[main]:org.hibernate.cfg.ConfigurationHHH000041:Configured
014. SessionFactory:null
015. 2015030323:01:00.042WARN[main]:org.hibernate.cfg.AnnotationBinderHHH000139:Illegal
016. useof@TableinasubclassofaSINGLE_TABLEhierarchy:com.jmdoudoux.test.hibernate.entity.
017. CompteCourant
018. 2015030323:01:00.043WARN[main]:org.hibernate.cfg.AnnotationBinderHHH000139:Illegal
019. useof@TableinasubclassofaSINGLE_TABLEhierarchy:com.jmdoudoux.test.hibernate.entity.
020. CompteEpargne
021. 2015030323:01:00.056INFO[main]:org.hibernate.service.jdbc.connections.internal.
022. DriverManagerConnectionProviderImplHHH000402:UsingHibernatebuiltinconnectionpool(not
023. forproductionuse!)
024. 2015030323:01:00.063INFO[main]:org.hibernate.service.jdbc.connections.internal.
025. DriverManagerConnectionProviderImplHHH000115:Hibernateconnectionpoolsize:1
026. 2015030323:01:00.063INFO[main]:org.hibernate.service.jdbc.connections.internal.
027. DriverManagerConnectionProviderImplHHH000006:Autocommitmode:false
028. 2015030323:01:00.064INFO[main]:org.hibernate.service.jdbc.connections.internal.
029. DriverManagerConnectionProviderImplHHH000401:usingdriver[com.mysql.jdbc.Driver]atURL[
030. jdbc:mysql://localhost:3307/mabdd]
031. 2015030323:01:00.064INFO[main]:org.hibernate.service.jdbc.connections.internal.
032. DriverManagerConnectionProviderImplHHH000046:Connectionproperties:{user=root,password=
033. ****}
034. 2015030323:01:00.367INFO[main]:org.hibernate.dialect.DialectHHH000400:Using
035. dialect:org.hibernate.dialect.MySQL5Dialect
036. 2015030323:01:00.397INFO[main]:org.hibernate.engine.transaction.internal.
037. TransactionFactoryInitiatorHHH000399:Usingdefaulttransactionstrategy(directJDBC
038. transactions)
039. 2015030323:01:00.402INFO[main]:org.hibernate.hql.internal.ast.
040. ASTQueryTranslatorFactoryHHH000397:UsingASTQueryTranslatorFactory
041. 2015030323:01:00.671INFO[main]:org.hibernate.tool.hbm2ddl.SchemaExportHHH000227:
042. Runninghbm2ddlschemaexport
043. Hibernate:droptableifexistscompte
044. Hibernate:droptableifexistshibernate_sequences
045. Hibernate:createtablecompte(DTYPEvarchar(31)notnull,idintegernotnull,numero
046. varchar(255),soldedecimal(19,2),decouvertinteger,tauxdecimal(19,2),primarykey(id))
047. Hibernate:createtablehibernate_sequences(sequence_namevarchar(255),
048. sequence_next_hi_valueinteger)
049. 2015030323:01:00.722INFO[main]:org.hibernate.tool.hbm2ddl.SchemaExportHHH000230:
050. Schemaexportcomplete
051. Hibernate:selectsequence_next_hi_valuefromhibernate_sequenceswheresequence_name='
052. compte'forupdate
053. Hibernate:insertintohibernate_sequences(sequence_name,sequence_next_hi_value)values('
054. compte',?)
055. Hibernate:updatehibernate_sequencessetsequence_next_hi_value=?where
056. sequence_next_hi_value=?andsequence_name='compte'
057. Hibernate:insertintocompte(numero,solde,DTYPE,id)values(?,?,'Compte',?)
058. Hibernate:insertintocompte(numero,solde,decouvert,DTYPE,id)values(?,?,?,'
059. CompteCourant',?)
060. Hibernate:insertintocompte(numero,solde,taux,DTYPE,id)values(?,?,?,'CompteEpargne'
061. ,?)
062. Recherched'uncompte
063. Hibernate:selectcompte0_.idasid0_0_,compte0_.numeroasnumero0_0_,compte0_.soldeas
064. solde0_0_,compte0_.decouvertasdecouvert0_0_,compte0_.tauxastaux0_0_,compte0_.DTYPEas
065. DTYPE0_0_fromcomptecompte0_wherecompte0_.id=?
066. com.jmdoudoux.test.hibernate.entity.Compte@af908f[id=1,numero=000012345000,solde=0.00]
067.
068. Recherched'uncomptecourant
069. Hibernate:selectcomptecour0_.idasid0_0_,comptecour0_.numeroasnumero0_0_,comptecour0_.
070. soldeassolde0_0_,comptecour0_.decouvertasdecouvert0_0_fromcomptecomptecour0_where
071. comptecour0_.id=?andcomptecour0_.DTYPE='CompteCourant'
072. com.jmdoudoux.test.hibernate.entity.CompteCourant@27723440CompteCourant[id=2,numero=
073. 000012345010,solde=1200.00,decouvert=2000]
https://www.jmdoudoux.fr/java/dej/chaphibernate.htm 64/105
24/04/2017 DvelopponsenJavaHibernate
073. 000012345010,solde=1200.00,decouvert=2000]
074.
075. Recherchepolymorphiqued'uncompte
076. Hibernate:selectcompte0_.idasid0_0_,compte0_.numeroasnumero0_0_,compte0_.soldeas
077. solde0_0_,compte0_.decouvertasdecouvert0_0_,compte0_.tauxastaux0_0_,compte0_.DTYPEas
078. DTYPE0_0_fromcomptecompte0_wherecompte0_.id=?
079. com.jmdoudoux.test.hibernate.entity.CompteEpargne@20700084CompteEpargne[id=3,numero=
080. 000012345020,solde=8000.00,taux=2.10]
081.
082. Recherchedetouslescomptes
083. Hibernate:selectcompte0_.idasid0_,compte0_.numeroasnumero0_,compte0_.soldeassolde0_,
084. compte0_.decouvertasdecouvert0_,compte0_.tauxastaux0_,compte0_.DTYPEasDTYPE0_from
085. comptecompte0_
086. com.jmdoudoux.test.hibernate.entity.Compte@164fc53[id=1,numero=000012345000,solde=0.00]
087. com.jmdoudoux.test.hibernate.entity.CompteCourant@13942651CompteCourant[id=2,numero=
088. 000012345010,solde=1200.00,decouvert=2000]
089. com.jmdoudoux.test.hibernate.entity.CompteEpargne@23542324CompteEpargne[id=3,numero=
090. 000012345020,solde=8000.00,taux=2.10]
091.
092. Recherchepolymorphiquedecomptes
093. Hibernate:selectcompte0_.idasid0_,compte0_.numeroasnumero0_,compte0_.soldeassolde0_,
094. compte0_.decouvertasdecouvert0_,compte0_.tauxastaux0_,compte0_.DTYPEasDTYPE0_from
095. comptecompte0_wherecompte0_.numerolike?
096. com.jmdoudoux.test.hibernate.entity.Compte@6ca594[id=1,numero=000012345000,solde=0.00]
097. com.jmdoudoux.test.hibernate.entity.CompteCourant@15384254CompteCourant[id=2,numero=
098. 000012345010,solde=1200.00,decouvert=2000]
099. com.jmdoudoux.test.hibernate.entity.CompteEpargne@4681268CompteEpargne[id=3,numero=
100. 000012345020,solde=8000.00,taux=2.10]

Rsultat :

01. mysql>select*fromcompte;
02. +++++++
03. |DTYPE|id|numero|solde|decouvert|taux|
04. +++++++
05. |Compte|1|000012345000|0.00|NULL|NULL|
06. |CompteCourant|2|000012345010|1200.00|2000|NULL|
07. |CompteEpargne|3|000012345020|8000.00|NULL|2.10|
08. +++++++
09. 3rowsinset(0.00sec)

54.11.2.2. Annotations, une table par classe concrte (TABLE_PER_CLASS)

Hibernate propose un support de la stratgie une table par classe concrte qui est dfinie comme tant optionnelle par JPA. Pour cela, il suffit
d'utiliser sur la classe mre l'annotation @Inheritance avec la proprit strategy initialise avec InheritanceType.TABLE_PER_CLASS.

Exemple ( code Java 5.0 ) :

01. packagecom.jmdoudoux.test.hibernate.entity;
02.
03. importjava.math.BigDecimal;
04. importjavax.persistence.Column;
05. importjavax.persistence.Entity;
06. importjavax.persistence.GeneratedValue;
07. importjavax.persistence.GenerationType;
08. importjavax.persistence.Id;
09. importjavax.persistence.Inheritance;
10. importjavax.persistence.InheritanceType;
11. importjavax.persistence.Table;
12.
13. @Entity
14. @Table(name="compte")
15. @Inheritance(strategy=InheritanceType.TABLE_PER_CLASS)
16. publicclassCompte{
17. @Id
18. @GeneratedValue(strategy=GenerationType.TABLE)

19. @Column(name="id")
https://www.jmdoudoux.fr/java/dej/chaphibernate.htm 65/105
24/04/2017 DvelopponsenJavaHibernate
19. @Column(name="id")
20. protectedintid;
21.
22. @Column(name="numero")
23. protectedStringnumero;
24.
25. @Column(name="solde")
26. protectedBigDecimalsolde;
27.
28. publicintgetId(){
29. returnid;
30. }
31.
32. publicvoidsetId(intid){
33. this.id=id;
34. }
35.
36. publicStringgetNumero(){
37. returnnumero;
38. }
39.
40. publicvoidsetNumero(Stringnumero){
41. this.numero=numero;
42. }
43.
44. publicBigDecimalgetSolde(){
45. returnsolde;
46. }
47.
48. publicvoidsetSolde(BigDecimalsolde){
49. this.solde=solde;
50. }
51.
52. @Override
53. publicStringtoString(){
54. returnsuper.toString()+"[id="+id+",numero="+numero+",solde="
55. +solde+"]";
56. }
57. }

Exemple ( code Java 5.0 ) :

01. packagecom.jmdoudoux.test.hibernate.entity;
02.
03. importjavax.persistence.AttributeOverride;
04. importjavax.persistence.AttributeOverrides;
05. importjavax.persistence.Column;
06. importjavax.persistence.Entity;
07. importjavax.persistence.Table;
08.
09. @Entity
10. @Table(name="compte_courant")
11. @AttributeOverrides({
12. @AttributeOverride(name="id",column=@Column(name="id")),
13. @AttributeOverride(name="numero",column=@Column(name="numero")),
14. @AttributeOverride(name="solde",column=@Column(name="solde"))})
15. publicclassCompteCourantextendsCompte{
16. @Column(name="decouvert")
17. privateintdecouvert;
18.
19. publicintgetDecouvert(){
20. returndecouvert;
21. }
22.
23. publicvoidsetDecouvert(intdecouvert){
24. this.decouvert=decouvert;
25. }
26.
27. @Override
28. publicStringtoString(){
29. returnthis.getClass().getName()+"@"+System.identityHashCode(this)
30. +"CompteCourant[id="+id+",numero="+numero+",solde="+solde
31. +",decouvert="+decouvert+"]";
32. }
33. }

Exemple ( code Java 5.0 ) :

01. packagecom.jmdoudoux.test.hibernate.entity;
02.
03. importjava.math.BigDecimal;
04. importjavax.persistence.AttributeOverride;
05. importjavax.persistence.AttributeOverrides;
06. importjavax.persistence.Column;
07. importjavax.persistence.Entity;
08. importjavax.persistence.Table;
09.
10. @Entity
11. @Table(name="compte_epargne")
12. @AttributeOverrides({
13. @AttributeOverride(name="id",column=@Column(name="id")),
14. @AttributeOverride(name="numero",column=@Column(name="numero")),
https://www.jmdoudoux.fr/java/dej/chaphibernate.htm 66/105
24/04/2017 DvelopponsenJavaHibernate
14. @AttributeOverride(name="numero",column=@Column(name="numero")),
15. @AttributeOverride(name="solde",column=@Column(name="solde"))})
16. publicclassCompteEpargneextendsCompte{
17. @Column(name="taux")
18. privateBigDecimaltaux;
19.
20. publicBigDecimalgetTaux(){
21. returntaux;
22. }
23.
24. publicvoidsetTaux(BigDecimaltaux){
25. this.taux=taux;
26. }
27.
28. @Override
29. publicStringtoString(){
30. returnthis.getClass().getName()+"@"+System.identityHashCode(this)
31. +"CompteEpargne[id="+id+",numero="+numero+",solde="
32. +solde+",taux="+taux+"]";
33. }
34. }

Dans les exemples ci-dessus, les annotations @AttributesOverrides et @AttributesOverride sont employes titre indicatif car elles utilisent les
valeurs par dfaut et pourraient donc tre retires.

Rsultat :

001. 2015030323:18:12.766INFO[main]:org.hibernate.annotations.common.VersionHCANN000001:
002. HibernateCommonsAnnotations{4.0.1.Final}
003. 2015030323:18:12.776INFO[main]:org.hibernate.VersionHHH000412:HibernateCore{4.1.
004. 4.Final}
005. 2015030323:18:12.779INFO[main]:org.hibernate.cfg.EnvironmentHHH000206:hibernate.
006. propertiesnotfound
007. 2015030323:18:12.780INFO[main]:org.hibernate.cfg.EnvironmentHHH000021:Bytecode
008. providername:javassist
009. 2015030323:18:12.814INFO[main]:org.hibernate.cfg.ConfigurationHHH000043:
010. Configuringfromresource:/hibernate.cfg.xml
011. 2015030323:18:12.814INFO[main]:org.hibernate.cfg.ConfigurationHHH000040:
012. Configurationresource:/hibernate.cfg.xml
013. 2015030323:18:12.891INFO[main]:org.hibernate.cfg.ConfigurationHHH000041:Configured
014. SessionFactory:null
015. 2015030323:18:13.080INFO[main]:org.hibernate.service.jdbc.connections.internal.
016. DriverManagerConnectionProviderImplHHH000402:UsingHibernatebuiltinconnectionpool(not
017. forproductionuse!)
018. 2015030323:18:13.087INFO[main]:org.hibernate.service.jdbc.connections.internal.
019. DriverManagerConnectionProviderImplHHH000115:Hibernateconnectionpoolsize:1
020. 2015030323:18:13.088INFO[main]:org.hibernate.service.jdbc.connections.internal.
021. DriverManagerConnectionProviderImplHHH000006:Autocommitmode:false
022. 2015030323:18:13.088INFO[main]:org.hibernate.service.jdbc.connections.internal.
023. DriverManagerConnectionProviderImplHHH000401:usingdriver[com.mysql.jdbc.Driver]atURL[
024. jdbc:mysql://localhost:3307/mabdd]
025. 2015030323:18:13.089INFO[main]:org.hibernate.service.jdbc.connections.internal.
026. DriverManagerConnectionProviderImplHHH000046:Connectionproperties:{user=root,password=
027. ****}
028. 2015030323:18:13.392INFO[main]:org.hibernate.dialect.DialectHHH000400:Using
029. dialect:org.hibernate.dialect.MySQL5Dialect
030. 2015030323:18:13.424INFO[main]:org.hibernate.engine.transaction.internal.
031. TransactionFactoryInitiatorHHH000399:Usingdefaulttransactionstrategy(directJDBC
032. transactions)
033. 2015030323:18:13.428INFO[main]:org.hibernate.hql.internal.ast.
034. ASTQueryTranslatorFactoryHHH000397:UsingASTQueryTranslatorFactory
035. 2015030323:18:13.736INFO[main]:org.hibernate.tool.hbm2ddl.SchemaExportHHH000227:
036. Runninghbm2ddlschemaexport
037. Hibernate:droptableifexistscompte
038. Hibernate:droptableifexistscompte_courant
039. Hibernate:droptableifexistscompte_epargne
040. Hibernate:droptableifexistshibernate_sequences
041. Hibernate:createtablecompte(idintegernotnull,numerovarchar(255),soldedecimal(19,2),
042. primarykey(id))
043. Hibernate:createtablecompte_courant(idintegernotnull,numerovarchar(255),solde
044. decimal(19,2),decouvertinteger,primarykey(id))
045. Hibernate:createtablecompte_epargne(idintegernotnull,numerovarchar(255),solde
046. decimal(19,2),tauxdecimal(19,2),primarykey(id))
047. Hibernate:createtablehibernate_sequences(sequence_namevarchar(255),
048. sequence_next_hi_valueinteger)
049. 2015030323:18:13.843INFO[main]:org.hibernate.tool.hbm2ddl.SchemaExportHHH000230:
050. Schemaexportcomplete
051. Hibernate:selectsequence_next_hi_valuefromhibernate_sequenceswheresequence_name='
052. compte'forupdate
053. Hibernate:insertintohibernate_sequences(sequence_name,sequence_next_hi_value)values('
054. compte',?)
055. Hibernate:updatehibernate_sequencessetsequence_next_hi_value=?where
056. sequence_next_hi_value=?andsequence_name='compte'
057. Hibernate:insertintocompte(numero,solde,id)values(?,?,?)
058. Hibernate:insertintocompte_courant(numero,solde,decouvert,id)values(?,?,?,?)
059. Hibernate:insertintocompte_epargne(numero,solde,taux,id)values(?,?,?,?)
060. Recherched'uncompte
061. Hibernate:selectcompte0_.idasid0_0_,compte0_.numeroasnumero0_0_,compte0_.soldeas
062. solde0_0_,compte0_.decouvertasdecouvert1_0_,compte0_.tauxastaux2_0_,compte0_.clazz_as
063. clazz_0_from(selectid,numero,solde,nullasdecouvert,nullastaux,0asclazz_from
064. compteunionselectid,numero,solde,decouvert,nullastaux,1asclazz_from
065. compte_courantunionselectid,numero,solde,nullasdecouvert,taux,2asclazz_from

066. compte_epargne)compte0_wherecompte0_.id=?
https://www.jmdoudoux.fr/java/dej/chaphibernate.htm 67/105
24/04/2017 DvelopponsenJavaHibernate
066. compte_epargne)compte0_wherecompte0_.id=?
067. com.jmdoudoux.test.hibernate.entity.Compte@198f6dd[id=1,numero=000012345000,solde=0.00]
068.
069. Recherched'uncomptecourant
070. Hibernate:selectcomptecour0_.idasid0_0_,comptecour0_.numeroasnumero0_0_,comptecour0_.
071. soldeassolde0_0_,comptecour0_.decouvertasdecouvert1_0_fromcompte_courantcomptecour0_
072. wherecomptecour0_.id=?
073. com.jmdoudoux.test.hibernate.entity.CompteCourant@3316864CompteCourant[id=2,numero=
074. 000012345010,solde=1200.00,decouvert=2000]
075.
076. Recherchepolymorphiqued'uncompte
077. Hibernate:selectcompte0_.idasid0_0_,compte0_.numeroasnumero0_0_,compte0_.soldeas
078. solde0_0_,compte0_.decouvertasdecouvert1_0_,compte0_.tauxastaux2_0_,compte0_.clazz_as
079. clazz_0_from(selectid,numero,solde,nullasdecouvert,nullastaux,0asclazz_from
080. compteunionselectid,numero,solde,decouvert,nullastaux,1asclazz_from
081. compte_courantunionselectid,numero,solde,nullasdecouvert,taux,2asclazz_from
082. compte_epargne)compte0_wherecompte0_.id=?
083. com.jmdoudoux.test.hibernate.entity.CompteEpargne@20376252CompteEpargne[id=3,numero=
084. 000012345020,solde=8000.00,taux=2.10]
085.
086. Recherchedetouslescomptes
087. Hibernate:selectcompte0_.idasid0_,compte0_.numeroasnumero0_,compte0_.soldeassolde0_,
088. compte0_.decouvertasdecouvert1_,compte0_.tauxastaux2_,compte0_.clazz_asclazz_from(
089. selectid,numero,solde,nullasdecouvert,nullastaux,0asclazz_fromcompteunion
090. selectid,numero,solde,decouvert,nullastaux,1asclazz_fromcompte_courantunion
091. selectid,numero,solde,nullasdecouvert,taux,2asclazz_fromcompte_epargne)compte0_
092. com.jmdoudoux.test.hibernate.entity.Compte@165d7a2[id=1,numero=000012345000,solde=0.00]
093. com.jmdoudoux.test.hibernate.entity.CompteCourant@30230592CompteCourant[id=2,numero=
094. 000012345010,solde=1200.00,decouvert=2000]
095. com.jmdoudoux.test.hibernate.entity.CompteEpargne@4358252CompteEpargne[id=3,numero=
096. 000012345020,solde=8000.00,taux=2.10]
097.
098. Recherchepolymorphiquedecomptes
099. Hibernate:selectcompte0_.idasid0_,compte0_.numeroasnumero0_,compte0_.soldeassolde0_,
100. compte0_.decouvertasdecouvert1_,compte0_.tauxastaux2_,compte0_.clazz_asclazz_from(
101. selectid,numero,solde,nullasdecouvert,nullastaux,0asclazz_fromcompteunion
102. selectid,numero,solde,decouvert,nullastaux,1asclazz_fromcompte_courantunion
103. selectid,numero,solde,nullasdecouvert,taux,2asclazz_fromcompte_epargne)compte0_
104. wherecompte0_.numerolike?
105. com.jmdoudoux.test.hibernate.entity.Compte@129d5bf[id=1,numero=000012345000,solde=0.00]
106. com.jmdoudoux.test.hibernate.entity.CompteCourant@26225329CompteCourant[id=2,numero=
107. 000012345010,solde=1200.00,decouvert=2000]
108. com.jmdoudoux.test.hibernate.entity.CompteEpargne@11121275CompteEpargne[id=3,numero=
109. 000012345020,solde=8000.00,taux=2.10]

Rsultat :

01. Enterpassword:****
02. WelcometotheMySQLmonitor.Commandsendwith;or\g.
03. YourMySQLconnectionidis73
04. Serverversion:5.6.15MySQLCommunityServer(GPL)
05.
06. Copyright(c)2000,2013,Oracleand/oritsaffiliates.Allrightsreserved.
07.
08. OracleisaregisteredtrademarkofOracleCorporationand/orits
09. affiliates.
10. Othernamesmaybetrademarksoftheirrespectiveowners.
11.
12. Type'help;'or'\h'forhelp.Type'\c'toclearthecurrentinputstatement.
13.
14. mysql>usemabdd
15. Databasechanged
16. mysql>select*fromcompte;
17. ++++
18. |id|numero|solde|
19. ++++
20. |1|000012345000|0.00|
21. ++++
22. 1rowinset(0.02sec)
23. mysql>select*fromcompte_courant;
24. +++++
25. |id|numero|solde|decouvert|
26. +++++
27. |2|000012345010|1200.00|2000|
28. +++++
29. 1rowinset(0.00sec)
30. mysql>select*fromcompte_epargne;
31. +++++
32. |id|numero|solde|taux|
33. +++++
34. |3|000012345020|8000.00|2.10|
https://www.jmdoudoux.fr/java/dej/chaphibernate.htm 68/105
24/04/2017 DvelopponsenJavaHibernate
34. |3|000012345020|8000.00|2.10|
35. +++++
36. 1rowinset(0.00sec)
37. mysql>

54.11.2.3. Annotations, une table par sous-classe (JOINED)

L'entit de la classe mre utilise la stratgie InheritanceType.JOINED grce l'annotation @Inheritance.

Exemple ( code Java 5.0 ) :

01. packagecom.jmdoudoux.test.hibernate.entity;
02.
03. importjava.math.BigDecimal;
04. importjavax.persistence.Column;
05. importjavax.persistence.Entity;
06. importjavax.persistence.GeneratedValue;
07. importjavax.persistence.Id;
08. importjavax.persistence.Inheritance;
09. importjavax.persistence.InheritanceType;
10. importjavax.persistence.Table;
11.
12. @Entity
13. @Table(name="compte")
14. @Inheritance(strategy=
15. InheritanceType.JOINED)
16. publicclassCompte{
17. @Id
18. @GeneratedValue
19. @Column(name="id")
20. protectedintid;
21.
22. @Column(name="numero")
23. protectedStringnumero;
24.
25. @Column(name="solde")
26. protectedBigDecimalsolde;
27.
28. publicintgetId(){
29. returnid;
30. }
31.
32. publicvoidsetId(intid){
33. this.id=id;
34. }
35.
36. publicStringgetNumero(){
37. returnnumero;
38. }
39.
40. publicvoidsetNumero(Stringnumero){
41. this.numero=numero;
42. }
43.
44. publicBigDecimalgetSolde(){
45. returnsolde;
46. }
47.
48. publicvoidsetSolde(BigDecimalsolde){
49. this.solde=solde;
50. }
51.
52. @Override
53. publicStringtoString(){
54. returnsuper.toString()+"[id="+id+",numero="+numero+",solde="
55. +solde+"]";
56. }
57. }

L'annotation @PrimaryKeyJoinColumn est utilise sur les classes filles pour prciser la colonne qui est la cl primaire et qui servira de cl trangre lors
de la jointure avec la table de la classe mre.

Exemple ( code Java 5.0 ) :

01. packagecom.jmdoudoux.test.hibernate.entity;
02.
03. importjavax.persistence.Column;
04. importjavax.persistence.Entity;
05. importjavax.persistence.PrimaryKeyJoinColumn;
06. importjavax.persistence.Table;
07.
08. @Entity
09. @Table(name="compte_courant")
10. @PrimaryKeyJoinColumn(name="id")
https://www.jmdoudoux.fr/java/dej/chaphibernate.htm 69/105
24/04/2017 DvelopponsenJavaHibernate
10. @PrimaryKeyJoinColumn(name="id")
11. publicclassCompteCourantextendsCompte{
12. @Column(name="decouvert")
13. privateintdecouvert;
14.
15. publicintgetDecouvert(){
16. returndecouvert;
17. }
18.
19. publicvoidsetDecouvert(intdecouvert){
20. this.decouvert=decouvert;
21. }
22.
23. @Override
24. publicStringtoString(){
25. returnthis.getClass().getName()+"@"+System.identityHashCode(this)
26. +"CompteCourant[id="+id+",numero="+numero+",solde="+solde
27. +",decouvert="+decouvert+"]";
28. }
29. }

Exemple ( code Java 5.0 ) :

01. packagecom.jmdoudoux.test.hibernate.entity;
02.
03. importjava.math.BigDecimal;
04. importjavax.persistence.Column;
05. importjavax.persistence.Entity;
06. importjavax.persistence.PrimaryKeyJoinColumn;
07. importjavax.persistence.Table;
08.
09. @Entity
10. @Table(name="compte_epargne")
11. @PrimaryKeyJoinColumn(name="id")
12. publicclassCompteEpargneextendsCompte{
13. @Column(name="taux")
14. privateBigDecimaltaux;
15.
16. publicBigDecimalgetTaux(){
17. returntaux;
18. }
19.
20. publicvoidsetTaux(BigDecimaltaux){
21. this.taux=taux;
22. }
23.
24. @Override
25. publicStringtoString(){
26. returnthis.getClass().getName()+"@"+System.identityHashCode(this)
27. +"CompteEpargne[id="+id+",numero="+numero+",solde="
28. +solde+",taux="+taux+"]";
29. }
30. }

Rsultat :

001. 2015030521:04:07.364INFO[main]:org.hibernate.annotations.common.VersionHCANN000001:
002. HibernateCommonsAnnotations{4.0.1.Final}
003. 2015030521:04:07.373INFO[main]:org.hibernate.VersionHHH000412:HibernateCore{4.1.
004. 4.Final}
005. 2015030521:04:07.375INFO[main]:org.hibernate.cfg.EnvironmentHHH000206:hibernate.
006. propertiesnotfound
007. 2015030521:04:07.377INFO[main]:org.hibernate.cfg.EnvironmentHHH000021:Bytecode
008. providername:javassist
009. 2015030521:04:07.405INFO[main]:org.hibernate.cfg.ConfigurationHHH000043:
010. Configuringfromresource:/hibernate.cfg.xml
011. 2015030521:04:07.405INFO[main]:org.hibernate.cfg.ConfigurationHHH000040:
012. Configurationresource:/hibernate.cfg.xml
013. 2015030521:04:07.463INFO[main]:org.hibernate.cfg.ConfigurationHHH000041:Configured
014. SessionFactory:null
015. 2015030521:04:07.641INFO[main]:org.hibernate.service.jdbc.connections.internal.
016. DriverManagerConnectionProviderImplHHH000402:UsingHibernatebuiltinconnectionpool(not
017. forproductionuse!)
018. 2015030521:04:07.648INFO[main]:org.hibernate.service.jdbc.connections.internal.
019. DriverManagerConnectionProviderImplHHH000115:Hibernateconnectionpoolsize:1
020. 2015030521:04:07.648INFO[main]:org.hibernate.service.jdbc.connections.internal.
021. DriverManagerConnectionProviderImplHHH000006:Autocommitmode:false
022. 2015030521:04:07.649INFO[main]:org.hibernate.service.jdbc.connections.internal.
023. DriverManagerConnectionProviderImplHHH000401:usingdriver[com.mysql.jdbc.Driver]atURL[
024. jdbc:mysql://localhost:3307/mabdd]
025. 2015030521:04:07.649INFO[main]:org.hibernate.service.jdbc.connections.internal.
026. DriverManagerConnectionProviderImplHHH000046:Connectionproperties:{user=root,password=
027. ****}
028. 2015030521:04:07.955INFO[main]:org.hibernate.dialect.DialectHHH000400:Using
029. dialect:org.hibernate.dialect.MySQL5Dialect
030. 2015030521:04:07.983INFO[main]:org.hibernate.engine.transaction.internal.
031. TransactionFactoryInitiatorHHH000399:Usingdefaulttransactionstrategy(directJDBC
032. transactions)
033. 2015030521:04:07.988INFO[main]:org.hibernate.hql.internal.ast.
034. ASTQueryTranslatorFactoryHHH000397:UsingASTQueryTranslatorFactory
035. 2015030521:04:08.211INFO[main]:org.hibernate.tool.hbm2ddl.SchemaExportHHH000227:
036. Runninghbm2ddlschemaexport
https://www.jmdoudoux.fr/java/dej/chaphibernate.htm 70/105
24/04/2017 DvelopponsenJavaHibernate
036. Runninghbm2ddlschemaexport
037. Hibernate:altertablecompte_courantdropforeignkeyFK2435FDBF9CCD1BB4
038. Hibernate:altertablecompte_epargnedropforeignkeyFK8E9D8D439CCD1BB4
039. Hibernate:droptableifexistscompte
040. Hibernate:droptableifexistscompte_courant
041. Hibernate:droptableifexistscompte_epargne
042. Hibernate:createtablecompte(idintegernotnullauto_increment,numerovarchar(255),solde
043. decimal(19,2),primarykey(id))
044. Hibernate:createtablecompte_courant(decouvertinteger,idintegernotnull,primarykey(
045. id))
046. Hibernate:createtablecompte_epargne(tauxdecimal(19,2),idintegernotnull,primarykey(
047. id))
048. Hibernate:altertablecompte_courantaddindexFK2435FDBF9CCD1BB4(id),addconstraint
049. FK2435FDBF9CCD1BB4foreignkey(id)referencescompte(id)
050. Hibernate:altertablecompte_epargneaddindexFK8E9D8D439CCD1BB4(id),addconstraint
051. FK8E9D8D439CCD1BB4foreignkey(id)referencescompte(id)
052. 2015030521:04:08.315INFO[main]:org.hibernate.tool.hbm2ddl.SchemaExportHHH000230:
053. Schemaexportcomplete
054. Hibernate:insertintocompte(numero,solde)values(?,?)
055. Hibernate:insertintocompte(numero,solde)values(?,?)
056. Hibernate:insertintocompte_courant(decouvert,id)values(?,?)
057. Hibernate:insertintocompte(numero,solde)values(?,?)
058. Hibernate:insertintocompte_epargne(taux,id)values(?,?)
059. Recherched'uncompte
060. Hibernate:selectcompte0_.idasid0_0_,compte0_.numeroasnumero0_0_,compte0_.soldeas
061. solde0_0_,compte0_1_.decouvertasdecouvert1_0_,compte0_2_.tauxastaux2_0_,casewhen
062. compte0_1_.idisnotnullthen1whencompte0_2_.idisnotnullthen2whencompte0_.idisnot
063. nullthen0endasclazz_0_fromcomptecompte0_leftouterjoincompte_courantcompte0_1_on
064. compte0_.id=compte0_1_.idleftouterjoincompte_epargnecompte0_2_oncompte0_.id=compte0_2_.
065. idwherecompte0_.id=?
066. com.jmdoudoux.test.hibernate.entity.Compte@24ad9b[id=1,numero=000012345000,solde=0.00]
067.
068. Recherched'uncomptecourant
069. Hibernate:selectcomptecour0_.idasid0_0_,comptecour0_1_.numeroasnumero0_0_,
070. comptecour0_1_.soldeassolde0_0_,comptecour0_.decouvertasdecouvert1_0_fromcompte_courant
071. comptecour0_innerjoincomptecomptecour0_1_oncomptecour0_.id=comptecour0_1_.idwhere
072. comptecour0_.id=?
073. com.jmdoudoux.test.hibernate.entity.CompteCourant@29984851CompteCourant[id=2,numero=
074. 000012345010,solde=1200.00,decouvert=2000]
075.
076. Recherchepolymorphiqued'uncompte
077. Hibernate:selectcompte0_.idasid0_0_,compte0_.numeroasnumero0_0_,compte0_.soldeas
078. solde0_0_,compte0_1_.decouvertasdecouvert1_0_,compte0_2_.tauxastaux2_0_,casewhen
079. compte0_1_.idisnotnullthen1whencompte0_2_.idisnotnullthen2whencompte0_.idisnot
080. nullthen0endasclazz_0_fromcomptecompte0_leftouterjoincompte_courantcompte0_1_on
081. compte0_.id=compte0_1_.idleftouterjoincompte_epargnecompte0_2_oncompte0_.id=compte0_2_.
082. idwherecompte0_.id=?
083. com.jmdoudoux.test.hibernate.entity.CompteEpargne@6285813CompteEpargne[id=3,numero=
084. 000012345020,solde=8000.00,taux=2.10]
085.
086. Recherchedetouslescomptes
087. Hibernate:selectcompte0_.idasid0_,compte0_.numeroasnumero0_,compte0_.soldeassolde0_,
088. compte0_1_.decouvertasdecouvert1_,compte0_2_.tauxastaux2_,casewhencompte0_1_.idisnot
089. nullthen1whencompte0_2_.idisnotnullthen2whencompte0_.idisnotnullthen0endas
090. clazz_fromcomptecompte0_leftouterjoincompte_courantcompte0_1_oncompte0_.id=
091. compte0_1_.idleftouterjoincompte_epargnecompte0_2_oncompte0_.id=compte0_2_.id
092. com.jmdoudoux.test.hibernate.entity.CompteCourant@15462959CompteCourant[id=2,numero=
093. 000012345010,solde=1200.00,decouvert=2000]
094. com.jmdoudoux.test.hibernate.entity.CompteEpargne@12544708CompteEpargne[id=3,numero=
095. 000012345020,solde=8000.00,taux=2.10]
096. com.jmdoudoux.test.hibernate.entity.Compte@fa8f2c[id=1,numero=000012345000,solde=0.00]
097.
098. Recherchepolymorphiquedecomptes
099. Hibernate:selectcompte0_.idasid0_,compte0_.numeroasnumero0_,compte0_.soldeassolde0_,
100. compte0_1_.decouvertasdecouvert1_,compte0_2_.tauxastaux2_,casewhencompte0_1_.idisnot
101. nullthen1whencompte0_2_.idisnotnullthen2whencompte0_.idisnotnullthen0endas
102. clazz_fromcomptecompte0_leftouterjoincompte_courantcompte0_1_oncompte0_.id=
103. compte0_1_.idleftouterjoincompte_epargnecompte0_2_oncompte0_.id=compte0_2_.idwhere
104. compte0_.numerolike?
105. com.jmdoudoux.test.hibernate.entity.CompteCourant@9037617CompteCourant[id=2,numero=
106. 000012345010,solde=1200.00,decouvert=2000]
107. com.jmdoudoux.test.hibernate.entity.CompteEpargne@27879211CompteEpargne[id=3,numero=
108. 000012345020,solde=8000.00,taux=2.10]
109. com.jmdoudoux.test.hibernate.entity.Compte@1a4654d[id=1,numero=000012345000,solde=0.00]

https://www.jmdoudoux.fr/java/dej/chaphibernate.htm 71/105
24/04/2017 DvelopponsenJavaHibernate
Rsultat :

01. Enterpassword:****
02. WelcometotheMySQLmonitor.Commandsendwith;or\g.
03. YourMySQLconnectionidis82
04. Serverversion:5.6.15MySQLCommunityServer(GPL)
05.
06. Copyright(c)2000,2013,Oracleand/oritsaffiliates.Allrightsreserved.
07.
08. OracleisaregisteredtrademarkofOracleCorporationand/oritsaffiliates.
09. Othernamesmaybetrademarksoftheirrespectiveowners.
10. Type'help;'or'\h'forhelp.Type'\c'toclearthecurrentinputstatement.
11. mysql>usemabdd
12. Databasechanged
13. mysql>select*fromcompte;
14. ++++
15. |id|numero|solde|
16. ++++
17. |1|000012345000|0.00|
18. |2|000012345010|1200.00|
19. |3|000012345020|8000.00|
20. ++++
21. 3rowsinset(0.00sec)
22. mysql>select*fromcompte_courant;
23. +++
24. |decouvert|id|
25. +++
26. |2000|2|
27. +++
28. 1rowinset(0.00sec)
29. mysql>select*fromcompte_epargne;
30. +++
31. |taux|id|
32. +++
33. |2.10|3|
34. +++
35. 1rowinset(0.00sec)
36. mysql>

54.12. Les caches d'Hibernate


Un volume important d'changes entre l'application et la base de donnes est frquemment l'origine des problmes de performance d'une application.

Le but d'un cache est de rduire les changes entre l'application et la base de donnes en stockant en mmoire les entits dj lues de la base de
donnes. Une lecture dans la base de donnes n'est alors ncessaire que lorsque l'entit n'est pas dj prsente dans le cache (si l'entit n'a jamais t
lue ou si l'entit a t retire du cache).

Le cache permet de stocker des donnes qui ont dj t lues de la base de donnes, ce qui permet de rduire les changes entre la base de donnes et
l'application lorsque celle-ci a de nouveau besoin des donnes. L'accs la mmoire est beaucoup plus rapide que l'accs la base de donnes surtout si
celui-ci ncessite un change utilisant le rseau.

Hibernate propose une fonctionnalit de mise en cache des donnes qui peut permettre, si elle est correctement configure et utilise, d'amliorer les
performances de l'application. Il est ncessaire de bien comprendre le mode de fonctionnement du cache pour l'utiliser bon escient et le configurer
en consquence: dans le cas contraire, les performances peuvent se dgrader de faon srieuse voire dramatique.

L'utilisation du cache peut donc tre une solution certaines problmatiques de performance frquemment rencontres lorsqu'Hibernate n'est pas bien
compris ou n'est pas utilis de manire optimale. Mme si ces deux critres sont parfaitement matriss, le cache peut tre utile pour amliorer les
performances dans certaines circonstances notamment lors de la lecture de donnes statiques dans la base de donnes.

Hibernate propose d'utiliser un cache pour plusieurs types de fonctionnalits de manire amliorer les performances en lecture et/ou criture des
entits dans la base de donnes:

cache de premier niveau: son utilisation est implicite car il est toujours actif et est utilis par dfaut. Implment dans la session, son champ
d'action est limit la transaction courante
cache de second niveau: son utilisation est optionnelle il doit tre activ et configur pour pouvoir tre utilis. Implment dans l'objet de
type SessionFactory, son champ d'action est l'application: il est donc utilisable par toutes les transactions
le cache des requtes: son utilisation est optionnelle il doit tre activ et configur pour pouvoir tre utilis. Sa mise en oeuvre utilise le cache
de second niveau.

Une bonne connaissance de la faon dont ces caches fonctionnent et de la manire dont ils interagissent avec les autres API est essentielle pour obtenir
les meilleurs rsultats. Activer le cache et configurer les entits est facile mais cela ne garantit pas de pouvoir tirer le meilleur parti des
fonctionnalits proposes par les caches d'Hibernate.

Un objet de type Session est une unit de travail, qui correspond une transaction ct base de donnes: elle stocke l'tat sur les entits suite des
lectures et/ou modifications et/ou suppressions. Ces modifications et suppressions sont transformes en requtes SQL pour tre reportes dans la
base de donnes. Le stockage de cet tat reprsente le premier niveau de cache d'Hibernate.

Dans le cache de premier niveau, implment dans la session, les entits sont directement stockes dans le cache. Si une entit est de nouveau
rcupre de la session alors qu'elle a dj t charge c'est le mme objet encapsulant l'entit qui est retourn. Ceci ne pose aucun problme puisque
la porte de la session est la transaction courante. Ce mode de fonctionnement est utilis jusqu' ce que la transaction soit termine ou que la mthode
flush de la session soit invoque.

https://www.jmdoudoux.fr/java/dej/chaphibernate.htm 72/105
24/04/2017 DvelopponsenJavaHibernate
Le cache de premier niveau est essentiellement utilis pour limiter le nombre de requtes SQL requises par la transaction: par exemple, si une entit
est modifie plusieurs fois durant la transaction, l'tat final de l'entit est stock dans la session qui ne gnrera qu'une seule requte SQL de type
update, par dfaut la fin de la transaction.

Le cache de second niveau stocke les objets lus de la base de donnes au niveau de l'objet SessionFactory: les entits sont donc partages entre les
transactions et utilisables au niveau de l'application. Dans ce cas, lorsqu'une transaction a besoin de lire une entit, si celle-ci est dj prsente dans le
cache alors l'excution d'une ou plusieurs requtes SQL est vite.

L'utilisation du cache de second niveau est optionnelle. La dure de vie du cache de second niveau est lie celle de l'application. La dure de vie des
entits contenues dans le cache est configurable selon le cache utilis. Le cache de second niveau requiert l'utilisation d'une implmentation d'un cache
par un tiers.

Par dfaut, si le cache de second niveau est activ, la recherche d'une entit se fait prioritairement dans le cache de premier niveau, puis dans le cache
de second niveau et enfin dans la base de donnes par l'excution d'une requte SQL.

Hibernate propose une fonctionnalit qui permet de mettre en cache le rsultat de requtes SQL. Cette fonctionnalit possde des contraintes mais
peut tre intressante dans certains cas de figure.

54.12.1. Des recommandations pour l'utilisation des caches

La bonne comprhension du mode de fonctionnement et de la configuration des caches d'Hibernate est importante pour permettre d'en tirer le meilleur
parti. C'est notamment le cas du cache de second niveau qui peut, en tant correctement configur et utilis, amliorer les performances d'Hibernate.

Attention: l'utilisation d'un cache ne peut pas tre l'unique solution aux problmes de performance avec Hibernate. Comme pour d'autres besoins, le
cache peut tre une solution pour certaines problmatiques de performances mais il induit aussi d'autres soucis (fraicheur des donnes, dure avant
l'invalidation des donnes, rplication des donnes dans un cluster, ...). De plus, mal utilis ou configur, l'utilisation du cache peut aussi dgrader les
performances ou poser des problmes d'accs concurrents.

La gestion de la fraicheur des donnes est une problmatique frquente lors de l'utilisation d'un cache mais elle devient cruciale dans le cas du cache
des entits d'Hibernate.

Gnralement par mconnaissance, Hibernate est souvent peru comme peu performant car gnrateur de nombreuses requtes SQL. Il est important
de connatre son mode de fonctionnement afin de s'y adapter pour obtenir les meilleurs rsultats. Sa premire approche est plutt facile mais elle
masque aux dveloppeurs un moteur complexe dont la connaissance du fonctionnement est requise pour ne pas tre du et mme pour ne pas avoir de
gros problmes d'utilisation gnralement relatifs la performance.

L'activation du cache de second niveau est facile mais il est trs important de bien comprendre comment il fonctionne dans les situations o il peut
s'appliquer pour viter d'avoir un surcot li l'utilisation du cache sans en obtenir les bnfices.

Il est aussi important de noter que les caches ne sont jamais informs des modifications qui sont faites sur les donnes de la base par des applications
tierces. Par exemple, Hibernate n'est pas capable de savoir si une donne mise en cache est modifie par une autre application ou par la base de
donnes elle-mme (excution de procdures stockes ou de triggers).

Si ce cas de figure se prsente, il est ncessaire de configurer la rgion pour qu'elle s'invalide priodiquement dans un dlais plutt court ceci afin de
rgulirement retirer les donnes qu'elle contient. Cette priodicit est dfinir selon les besoins.

54.12.2. Les diffrents caches d'Hibernate

Plusieurs actions peuvent faire raliser une requte de type SQL par Hibernate:

obtenir une entit par son identifiant, par exemple en utilisant la mthode find() ou get()
obtenir une entit lors du parcours d'une relation puisque par dfaut seuls leurs identifiants sont encapsuls dans un objet de type proxy
obtenir une entit en utilisant une requte HQL ou l'API Criteria

L'utilisation d'un cache a pour but d'amliorer les performances: il se place entre l'application et la base de donnes pour stocker des donnes et ainsi
viter de les rechercher systmatiquement de la base de donnes. L'objectif principal des caches est de limiter la rptition des requtes de type
select en stockant les entits lues pour les obtenir du cache lors des invocations suivantes.

Hibernate propose deux types de caches, chacun ayant un but prcis :

le cache de niveau 1 ou cache de premier niveau: il est toujours actif car il est implment dans la classe Session. La visibilit de ce cache est la
transaction. Sa dure de vie est donc celle de la session. Le but est de rduire le nombre de requtes SQL d'une mme transaction.
le cache de niveau 2ou cache de second niveau : il n'est pas actif par dfaut. Il est implment dans la SessionFactory. La visibilit de ce cache
est l'application. Une fois activ, sa dure de vie est celle de l'instance de type SessionFactory. Le rle principal du cache de second niveau est
de partager des donnes entre sessions.

L'utilisation du cache de premier niveau est obligatoire puisqu'il est implment dans l'objet de type Session : toutes les requtes permettant
l'obtention ou la mise jour des donnes passent par la session. Une fois que la session est ferme, le contenu du cache de premier niveau est effac.

Pour rduire les changes entre l'application et la base de donnes, le cache de second niveau conserve les donnes lues de la base de donnes pour les
partager entre les sessions. Ces donnes stockes au niveau de la SessionFactory sont donc accessibles par toutes les sessions, vitant ainsi l'excution
de requtes SQL si les rsultats de celles-ci sont dj dans le cache.

Le cache de second niveau est optionnel. Le cache de premier niveau est toujours consult avant de consulter de cache de second niveau.

https://www.jmdoudoux.fr/java/dej/chaphibernate.htm 73/105
24/04/2017 DvelopponsenJavaHibernate
Le cache de second niveau peut tre utilis pour stocker trois types d'lmentscorrespondant trois cas d'utilisations du cache:

les entits (class cache)


les associations de type many (collection cache)
le rsultat des requtes (query cache)

L'implmentation du cache de second niveau requiert l'utilisation d'une solution de cache d'un tiers. Cette solution doit proposer une classe qui
implmente l'interface org.hibernate.cache.CacheProvider.

La configuration du cache de second niveau requiert plusieurs tapes:

dfinir les stratgies transactionnelles qui devront tre utilises par le cache de second niveau pour chaque entit et association
choisir une implmentation du cache qui supporte la ou les stratgies requises en plus des critres de choix plus gnraux (fiabilit,
performance, fonctionnalits, documentation, ...)
configurer Hibernate pour utiliser le cache
configurer de manire spcifique le cache

Le cache des requtes permet de conserver le rsultat de l'excution des requtes. Ce cache utilise la requte avec ses paramtres comme cl
laquelle il associe uniquement les identifiants et les types des entits qui sont obtenus lors de l'excution de la requte. Il repose sur l'utilisation du
cache de second niveau pour obtenir les donnes des entits concernes.

L'utilisation du cache des requtes est optionnelle: il n'est pas activ par dfaut. Il requiert la dfinition de deux rgions particulires dans le cache
de second niveau:

la premire stocke les rsultats (identifiants et types) des requtes


la seconde stocke le timestamp de dernire mise jour de chaque table

Ce cache est essentiellement utile pour les requtes frquemment excutes avec les mmes valeurs de paramtres.

54.12.2.1. La base des exemples de cette section

Les exemples de cette section utilisent la version 4.1 d'Hibernate.

Cette section va utiliser une petite application qui accde une base de donnes composes de deux tables : pays et devise. Le besoin fonctionnel
prcise qu'l existe une relation 1-N entre devise et pays partant du principe qu'un pays possde une devise et qu'une devise peut tre utilise par
plusieurs pays.

Exemple :

01. <?xmlversion="1.0"encoding="UTF8"?>
02. <!DOCTYPEhibernatemappingPUBLIC"//Hibernate/Hibernate
03. MappingDTD//EN""http://hibernate.org/dtd/hibernatemapping3.0.dtd">
04.
05. <hibernatemapping>
06. <classname="com.jmdoudoux.test.hibernatecache.entity.Pays"
07. table="pays">
08. <idname="id"column="id"type="int">
09. <generatorclass="identity"/>
10. </id>
11. <propertyname="codeIso"column="code_iso"
12. notnull="true"type="string"/>
13. <propertyname="nom"notnull="true"type="string"/>
14. <manytoonename="devise"column="FK_DEVISE"
15. class="com.jmdoudoux.test.hibernatecache.entity.Devise"/>
16. </class>
17. </hibernatemapping>

Exemple :

01. <?xmlversion="1.0"encoding="UTF8"?>
02. <!DOCTYPEhibernatemappingPUBLIC"//Hibernate/HibernateMapping
03. DTD//EN""http://hibernate.org/dtd/hibernatemapping3.0.dtd">
04.
05. <hibernatemapping>
06. <classname="com.jmdoudoux.test.hibernatecache.entity.Devise"
07. table="DEVISE">
08. <idname="id"column="ID">
09. <generatorclass="identity"/>
10. </id>
11. <propertyname="code"column="CODE"/>
12. <propertyname="libelle"column="LIBELLE"/>
13. <setname="pays">
14. <keycolumn="FK_DEVISE"/>
15. <onetomanyclass="com.jmdoudoux.test.hibernatecache.entity.Pays"/>
16. </set>
17. </class>
18. </hibernatemapping>

Dans le fichier de configuration d'Hibernate, le cache de second niveau est dsactiv et l'affichage des requtes SQL excutes est demand.
https://www.jmdoudoux.fr/java/dej/chaphibernate.htm 74/105
24/04/2017 DvelopponsenJavaHibernate

Rsultat :

01. <?xmlversion='1.0'encoding='utf8'?>
02. <!DOCTYPEhibernateconfigurationSYSTEM
03. "http://hibernate.org/dtd/hibernateconfiguration3.0.dtd">
04. <hibernateconfiguration>
05. <sessionfactory>
06. <!Databaseconnectionsettings>
07. <propertyname="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
08. <propertyname="hibernate.connection.url">jdbc:mysql://localhost:3306/mabdd</property>
09. <propertyname="hibernate.connection.username">root</property>
10. <propertyname="hibernate.connection.password"></property>
11. <propertyname="hibernate.connection.pool_size">1</property>
12. <propertyname="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>
13. <propertyname="hibernate.current_session_context_class">thread</property>
14. <!Cachedesecondniveaudsactiv>
15. <propertyname="hibernate.cache.provider_class">
16. org.hibernate.cache.internal.NoCacheProvider</property>
17. <!AfficherlesrequtesSQLexcutessurlasortiestandard>
18. <propertyname="hibernate.show_sql">true</property>
19. <mappingresource="Pays.hbm.xml"/>
20. <mappingresource="Devise.hbm.xml"/>
21. </sessionfactory>
22. </hibernateconfiguration>

54.12.2.2. Le cache de premier niveau

Le cache de premier niveau est implment dans la classe Session. Hibernate l'utilise par dfaut pour maintenir l'tat des entits lues et modifies
dans la transaction courante.

Une entit est stocke dans le cache de la session, c'est -dire le cache de premier niveau, chaque fois:

que les mthodes load() ou get() sont invoques


que les mthodes save(), update() ou saveOrUpdate() sont invoques

Le cache de premier niveau est activ par dfaut et il n'est pas possible de le dsactiver.

Le cache de premier niveau permet Hibernate de conserver les donnes lues et celles qui sont modifies : ceci permet de limiter le nombre de
requtes excutes pour les lectures et les mises jour sur la base de donnes.

Grce au cache de premier niveau, sur une mme session, plusieurs invocations de la mthode get() qui retourneraient la mme entit ne ncessiteront
qu'une seule requte SQL lors de la premire invocation. Pour les invocations suivantes, les donnes seront obtenues directement du cache sans
relecture dans la base de donnes.

Exemple :

01. publicstaticvoidlirePaysDeuxFois()throwsException{
02. Sessionsession=sessionFactory.openSession();
03. Transactiontx=null;
04. try{
05. tx=session.beginTransaction();
06. Payspays=(Pays)session.load(Pays.class,newInteger(4));
07. System.out.println("pays:id="+pays.getId()+"codeIso="
08. +pays.getCodeIso()+"nom="+pays.getNom());
09. pays=(Pays)session.load(Pays.class,newInteger(4));
10. System.out.println("pays:id="+pays.getId()+"codeIso="
11. +pays.getCodeIso()+"nom="+pays.getNom());
12. tx.commit();
13. }catch(Exceptione){
14. if(tx!=null){
15. tx.rollback();
16. }
17. throwe;
18. }finally{
19. session.close();
20. }
21. }

Rsultat :

1. Hibernate:selectpays0_.idas
2. id0_0_,pays0_.code_isoascode2_0_0_,pays0_.nomasnom0_0_,pays0_.FK_DEVISE
3. asFK4_0_0_frompayspays0_wherepays0_.id=?
4. pays:id=4codeIso=LU
5. nom=Luxembourg
6. pays:id=4codeIso=LU
7. nom=Luxembourg

https://www.jmdoudoux.fr/java/dej/chaphibernate.htm 75/105
24/04/2017 DvelopponsenJavaHibernate
Bien que la mthode load() soit invoque deux fois, l'entit n'est lue qu'une seule fois dans la base de donnes et est stocke dans le cache de premier
niveau. Lors de la seconde invocation de la mthode load(), l'entit est obtenue du cache de premier niveau vitant ainsi une seconde lecture dans la
base de donnes.

Hibernate utilise toujours de manire transparente le cache de premier niveau.

L'interface Session propose plusieurs mthodes pour grer le contenu du cache de premier niveau.

Lorsque la mthode flush() de la session est invoque, l'tat des entits contenues dans la session est synchronis dans la base de donnes. Ces entits
restent dans la session jusqu' sa fermeture.

La mthode contains() renvoie un boolen qui prcise si une instance d'une entit est associe la session.

La mthode clear() permet de supprimer toutes les entits contenues dans la session.

La mthode evict() permet de retirer une entit de la session et les entits qui lui sont associes si l'attribut cascade de l'association pour valeur all
ou all-delete-orphan. Cette mthode est particulirement pratique lorsque des requtes retournent de nombreuses entits et que ces dernires peuvent
tre retires du cache car devenues inutiles.

54.12.2.3. Le cache de second niveau

Ds que l'on utilise le cache de second niveau, il ne faut pas oublier que le cache de premier niveau est toujours actif. Hibernate tente de trouver une
entit dans le cache de premier niveau, si elle n'est pas trouve, Hibernate tente de la trouver dans le cache de second niveau. Si elle n'est toujours pas
trouve alors elle est lue de la base de donnes.

L'utilisation du cache de premier niveau est transparente car compltement prise en charge par Hibernate. L'utilisation du cache de second niveau est
plus complexe: les donnes contenues dans le cache sont partages entre les transactions et peuvent mme tre partages entre plusieurs JVM.

Le cache de second niveau est partag entre toutes les sessions alors que la porte du cache de premier niveau est au niveau d'une seule session.
Hibernate propose une API pour permettre de choisir l'implmentation du cache qui sera utilise pour le cache de second niveau.

Le cache de second niveau est implment dans un objet de type SessionFactory: gnralement une application ne possde qu'une seule instance de ce
type d'objet. La dure de vie du cache de second niveau est donc lie la dure de vie de l'instance de type SessionFactory. L'accs cet objet est
commun toutes les sessions. Le contenu du cache de second niveau peut donc tre partag entre plusieurs sessions.

La porte du cache de second niveau est la JVM ou un cluster si l'implmentation du cache supporte l'utilisation dans ce cadre.

Le cache de second niveau propose un mcanisme puissant qui peut permettre, dans des cas prcis, d'amliorer les performances d'une application.
Cependant, l'utilisation du cache de second niveau introduit une complexit supplmentaire: par exemple, l'utilisation de caches augmente toujours le
risque d'obtenir des donnes inconsistantes.

Les donnes en lecture seule dans le cache sont faciles utiliser et grer. Dans le cache, la gestion et l'utilisation des donnes pouvant tre mises
jour est plus dlicate.

L'usage du cache de second niveau le rend surtout intressant pour des donnes en lecture seule. Des donnes contenues dans le cache pouvant tre
mises jour risque de ne pas tre fraches. Il est alors trs important de bien dfinir la politique d'viction des entres dans le cache, surtout si la
fracheur des donnes est importante.

Les objets lus de la base de donnes peuvent tre stocks dans le cache de second niveau et ainsi tre partags par les sessions pour viter leur
relecture par les autres sessions. Bien sr ce partage est facile si les donnes sont uniquement lues et jamais modifies. Ce partage est plus complexe
lorsque les donnes peuvent tre mises jour par une session.

Le cache de second niveau ne peut jamais tre inform d'une modification ralise sans utiliser Hibernate. C'est le cas notamment si ces modifications
sont ralises par d'autres applications, des procdures stockes, des triggers, ... Dans ce cas, il faut utiliser des mcanismes qui permettent de
supprimer une entit du cache ou le contenu d'une rgion ou prvoir des suppressions priodiques du contenu du cache.

Hibernate impose une utilisation slective du cache de second niveau car il ne peut pas tre appliqu sur toutes les oprations. Le cache de second
niveau ne s'utilise que sur trois types d'lments:

les donnes des entits


les associations de type many
le rsultat des requtes

Par dfaut, le cache de second niveau n'est pas activ: pour l'utiliser, il est ncessaire de l'activer et de le configurer. Une fois le cache de second
niveau activ, seuls les lments configurs (entits, associations, requtes) pourront y tre stocks.

Le cache de premier niveau stocke directement les instances des entits. Le cache de second niveau, lui, stocke les entits sous une forme srialise.
Les entits ne sont pas stockes sous la forme d'instance : Hibernate stocke les attributs de l'entit sous une forme nomme tat dshydrat
(dehydrated state). Lorsqu'une entit est obtenue du cache, une nouvelle instance est cre partir des informations stockes dans le cache. La cl
dans le cache est l'identifiant de l'entit et la valeur est la forme dshydrate de l'entit.

Il est trs important de comprendre le fonctionnement du cache de second niveau pour en tirer le meilleur parti.

54.12.3. La configuration du cache de second niveau

https://www.jmdoudoux.fr/java/dej/chaphibernate.htm 76/105
24/04/2017 DvelopponsenJavaHibernate
Par dfaut, le cache de second niveau n'est pas activ. Son activation se fait en modifiant la configuration d'Hibernate.

La proprit hibernate.cache.use_second_level permet d'activer le cache de second niveau en lui affectant la valeur true.

Hibernate propose une solution de type plug-in pour lui permettre d'utiliser une implmentation d'un cache tiers comme cache de second niveau.

Hibernate offre une implmentation reposant sur un objet de type HashTable mais son utilisation n'est pas recommande car elle ne propose pas les
fonctionnalits minimum d'un cache (gestion de sa taille, de la dure de vie des lments contenus, ...)

La plupart des principaux caches open source peuvent s'utiliser avec Hibernate moyennant un peu de configuration. Une partie de cette configuration
est faite dans le fichier de configuration d'Hibernate en utilisant plusieurs proprits.

La proprit hibernate.cache.provider_class permet de prciser le nom pleinement qualifi de la classe du fournisseur du cache jusqu' la version 3.2
d'Hibernate.

Exemple pour ne prciser aucun fournisseur

Exemple :

1. <property
2. name="hibernate.cache.provider_class">org.hibernate.cache.internal.NoCacheProvider</property>

A partir de la version 3.3, c'est la proprit hibernate.cache.region.factory_class qui doit tre utilise.

Exemple pour ne prciser aucun fournisseur

Exemple :

1. <propertyname="hibernate.cache.region.factory_class">
2. org.hibernate.cache.internal.NoCachingRegionFactory</property>

La proprit hibernate.cache.use_structured_entries la valeur true permet de demander Hibernate destocker les donnes dans le cache de manire
lisible.

La proprit hibernate.cache.use_minimal_puts permet de demander Hibernate de limiter les critures dans le cache, ce qui entrainera plus de
lectures dans la base de donnes. La valeur true est intressante pour les caches en cluster.

La proprit hibernate.cache.use.region_prefix permet de prciser un prfixe qui sera utilis pour le nom de chaque rgion du cache de second niveau.

La proprit hibernate.cache.defaut_cache_concurrency_strategy permet de prciser la stratgie d'usage transactionnel utilise par l'annotation
@Cache. Il est possible de remplacer cette stratgie dfinie par dfaut en utilisant l'attribut strategy de l'annotation @Cache.

54.12.3.1. Les diffrents caches supports par Hibernate

Hibernate fournit en standard une implmentation du cache utilisant des objets de type HashTable : c'est une solution minimaliste qu'il n'est pas
recommand d'utiliser en production.

Hibernate propose le support en standard de plusieurs solutions open source comme implmentation du cache de second niveau:

Terracotta Ehcache (Easy Hibernate Cache)


OSCache (Open Symphony Cache)
Swarm Cache
JBoss Tree Cache: cache utilisable en cluster qui ncessite un gestionnaire de transactions

Chacun de ces caches possde des caractristiques et des fonctionnalits:

Ehcache : lger, rapide, facile configurer et utiliser, supporte les stratgies read-only, nonstrict-read-only et read-write, cache mmoire
avec dbordement sur disque, support du cluster
OSCache: supporte les stratgies read-only et read-write, cache mmoire avec dbordement sur disque, support du cluster en utilisant JGroups
ou JMS
SwarmCache: supporte les stratgies read-only et nonstrict-read-write, support du cluster en utilisant JGroups, appropri pour des applications
qui ralisent plus de lectures que d'critures
JBoss TreeCache : riche en fonctionnalits et rpliqu, supporte la stratgie transactional, utilisation de la classe
org.hibernate.cache.TreeCacheProvider (pour la version 1) et org.hibernate.cache.jbc.JbossCacheRegionFactory (pour la version 2)

Avant la version 3.2, Hibernate utilisait par dfaut Ehcache. A partir de la version 3.2 d'Hibernate, il n'y a plus d'implmentation par dfaut: celle
utiliser doit tre explicitement prcise dans la configuration d'Hibernate.

Hibernate impose de n'utiliser qu'une seule implmentation pour le cache de second niveau : il faut donc la choisir judicieusement en fonction des
besoins.

Cache Type Support en Cluster Cache de requtes support

Hashtable (ne pas utiliser en production) Mmoire Oui

https://www.jmdoudoux.fr/java/dej/chaphibernate.htm 77/105
24/04/2017 DvelopponsenJavaHibernate

Cache Type Support en Cluster Cache de requtes support

Ehcache Mmoire, disque Oui Oui

OSCache Mmoire, disque Oui

SwarmCache En cluster (multicast ip) Oui (invalidation de cluster)

JBoss TreeCache En cluster (multicast ip), transactionnel Oui (replication) Oui

54.12.3.2. La configuration du cache de second niveau

Une implmentation du cache doit fournir une classe qui implmente l'interface org.hibernate.cache.CacheProvider (jusqu' la version 3.2) ou l'interface
org.hibernate.RegionFactory ( partir de la version 3.3).

Il est ncessaire de prciser la classe du fournisseur qui doit tre utilise en donnant son nom pleinement qualifi comme valeur d'une proprit dans le
fichier de configuration d'Hibernate.

La configuration du cache de second niveau est diffrente selon la version d'Hibernate utilise :

Jusqu' la version 3.2, il faut utiliser la proprit hibernate.cache.provider_class


A partir de la version 3.3, il faut utiliser la proprit hibernate.cache.region.factory_class

L'exemple ci-dessous permet d'utiliser le cache Ehcache avec Hibernate 3.2.

Exemple :

1. <property
2. name="hibernate.cache.provider_class">org.hibernate.cache.EhCacheProvider</property>

La configuration du cache dpend de l'implmentation utilise.

Par dfaut, la rgion utilise est celle dfinie par dfaut dans le cache. Il est aussi possible de dfinir et configurer des rgions ddies.

Hibernate utilise des conventions de nommage particulires pour les noms des rgions du cache :

pour les entits : c'est le nom pleinement qualifi de la classe de l'entit


pour les associations : c'est le nom pleinement qualifi de la classe de l'entit, suivi d'un caractre point, suivi du nom du champ de la collection
pour les requtes : Hibernate utilise par dfaut deux rgions (StandardQueryCache et UpdateTimestampsCache).

Le nom de ces deux rgions est diffrent selon la version d'Hibernate utilise :

jusqu' Hibernate version 3.1 : net.sf.hibernate.cache.StandardQueryCache et net.sf.hibernate.cache.UpdateTimestampsCache


partir de la version 3.2 : org.hibernate.cache.StandardQueryCache et org.hibernate.cache.UpdateTimestampsCache

54.12.3.3. La configuration du cache Ehcache

La version d'Ehcache utilise dans cette section est la version 2.4.3.

Dans le fichier de configuration d'Hibernate, il faut activer l'utilisation du cache de second niveau avec Ehcache en donnant la valeur de la proprit
hibernate.cache.region.factory_class le nom pleinement qualifi d'une classe qui hrite de AbstractEhcacheRegionFactory.

Deux implmentations sont fournies par Hibernate dans la bibliothque hibernate-ehcache-xxx.jar:

org.hibernate.cache.ehcache.EhCacheRegionFactory
org.hibernate.cache.ehcache.SingletonEhCacheRegionFactory: cette implmentation est utiliser lorsqu'une seule configuration est requise. Il
ne faut pas l'utiliser si plusieurs instances d'Hibernate sont requises.

Exemple :

01. <?xmlversion='1.0'encoding='utf8'?>
02. <!DOCTYPEhibernateconfigurationSYSTEM
03. "http://hibernate.org/dtd/hibernateconfiguration3.0.dtd">
04. <hibernateconfiguration>
05. <sessionfactory>
06. <!...>
07. <!Cachedesecondniveauactivavecehcache>
08. <!propertyname="hibernate.cache.provider_class">
09. org.hibernate.cache.internal.NoCacheProvider</property>
10. <propertyname="hibernate.cache.region.factory_class">
11. org.hibernate.cache.ehcache.SingletonEhCacheRegionFactory</property>
12. <!...>
13. </sessionfactory>
14. </hibernateconfiguration>
https://www.jmdoudoux.fr/java/dej/chaphibernate.htm 78/105
24/04/2017 DvelopponsenJavaHibernate

EhCache fournit aussi sa propre implmentation qui est diffrente selon la version d'Hibernate utilise.

Jusqu' la version 3.2 incluse, il faut utiliser la classe net.sf.ehcache.hibernate.EhCacheProvider ou la classe


net.sf.ehcache.hibernate.SingletonEhCacheProvider comme valeur de la proprit hibernate.cache.provider_class.

A partir de la version 3.3, il faut utiliser la classe net.sf.ehcache.hibernate.EhCacheRegionFactory ou la classe


net.sf.ehcache.hibernate.SingletonEhCacheRegionFactory comme valeur de la proprit hibernate.cache.region.factory_class.

La configuration d'EhCache se fait dans un fichier XML nomm par dfaut ehcache.xml qui doit tre dans le classpath. Cette configuration porte sur
EhCache lui-mme, la rgion par dfaut et ventuellement chaque rgion utilise.

Le tag racine de ce document XML est <ehcache>.

Le tag <diskStore> permet de configurer le stockage sur disque des donnes du cache.

L'attribut path permet de prciser le chemin du rpertoire dans le lequel EhCache va stocker les donnes du cache sur disque.

EhCache cr selon la configuration des fichiers pour chaque cache concern avec l'extension .index et .data.

Le tag <defaultCache> permet de configurer le cache par dfaut.

Exemple :

1. <?xmlversion="1.0"encoding="UTF8"?>
2. <ehcache>
3. <diskStorepath="C:\temp\cache"/>
4. <defaultCachemaxElementsInMemory="100"eternal="false"
5. timeToIdleSeconds="120"timeToLiveSeconds="120"overflowToDisk="true"/>
6. </ehcache>

La proprit net.sf.ehcache.configurationResourceName du fichier de configuration permet de prciser le nom du chemin du fichier de configuration
d'EhCache.

Il est ncessaire de configurer la rgion par dfaut et ventuellement des rgions ddies.

Par dfaut, Hibernate va rechercher et utiliser une rgion dont le nom est le nom pleinement qualifi de l'entit qui doit tre mise en cache. Si elle
n'est pas trouve, alors la rgion par dfaut sera utilise.

Rsultat :

1. WARN
2. [main]:org.hibernate.cache.ehcache.AbstractEhcacheRegionFactory
3. HHH020003:Couldnotfindaspecificehcacheconfigurationforcachenamed
4. [com.jmdoudoux.test.hibernatecache.entity.Pays];usingdefaults.

La configuration d'une rgion se fait en utilisant le tag <cache>.

La configuration peut se faire en utilisant plusieurs attributs:

Attribut Rle

name Le nom du cache. Il doit tre unique et sera utilis par Hibernate comme la dsignation d'une rgion

Prciser le nombre d'lments maximum que peut contenir la rgion en mmoire. Si le maximum est atteint et
maxElementsInMemory qu'un nouvel lment doit tre insr, alors il y a une viction d'un lment selon la configuration. La valeur par
dfaut est 0, indiquant un nombre infini

timeToIdleSeconds Dure de vie en secondes des objets inaccds (TTI). La valeur par dfaut est 0, indiquant un temps infini

Dure de vie en secondes des objets dans le cache quelque soit leur utilisation ou non (TTL) . La valeur par dfaut
timeToLiveSeconds
est 0, indiquant un temps infini

true ou false. La valeur true permet de prciser que les donnes contenues dans la rgion ne peuvent pas tre
eternal
retires. Ce paramtre est prioritaire sur les TTI et TTL si sa valeur est true

overflowToDisk true ou false: criture d'lments sur le systme de fichiers si la rgion contient trop d'lments

true ou false. La valeur permet de demander de conserver les donnes crites sur le systme de fichiers lorsque
diskPersistent
la JVM est redmarre. La valeur par dfaut est false

Prciser l'intervalle en secondes entre chaque excution de la rgle d'viction des donnes du cache sur disque.
diskExpiryThreadIntervalSeconds
La valeur par dfaut est 120.

memoryStoreEvictionPolicy Rgle appliquer pour l'viction de donnes lorsque la taille maximale du cache est atteinte. Les rgles possibles
sont:

LRU (Least Recently Used)


FIFO (First In First Out)
LFU (Least Frequently Used)

https://www.jmdoudoux.fr/java/dej/chaphibernate.htm 79/105
24/04/2017 DvelopponsenJavaHibernate

Prciser le nombre maximum d'lments du cache sur disque. La valeur par dfaut est 0, indiquant un nombre
maxElementsOnDisk
illimit

Prciser la taille d'un tampon qui est utilis pour stocker temporairement les donnes crire de manire
diskSpoolBufferSizeMB
asynchrone sur disque. Chaque cache possde son propre tampon. La taille par dfaut est 30Mo.

Il est important de bien tenir compte dans la configuration de l'expiration des donnes du cache.

Le paramtre TTI permet notamment de retirer du cache des lments qui sont peu frquemment utiliss et ainsi faire de la place aux nouveux
lments.

Le paramtre TTL permet de rafrachir priodiquement des donnes en forant leur viction de manire rpte.

Exemple :

01. <?xmlversion="1.0"encoding="UTF8"?>
02. <ehcache>
03. <diskStorepath="C:\temp\cache"/>
04. <defaultCachemaxElementsInMemory="100"eternal="false"
05. timeToIdleSeconds="120"timeToLiveSeconds="120"overflowToDisk="true"/>
06. <cachename="com.jmdoudoux.test.hibernatecache.entity.Pays"
07. maxElementsInMemory="250"eternal="true"overflowToDisk="false"/>
08. <cachename="com.jmdoudoux.test.hibernatecache.entity.Section"
09. maxElementsInMemory="100"eternal="false"timeToIdleSeconds="300"
10. timeToLiveSeconds="600"overflowToDisk="true"/>
11. </ehcache>

Un message est affich dans le journal pour chaque entit configure dans le cache EhCache.

Rsultat :

1. WARN
2. [main]:org.hibernate.cache.ehcache.internal.strategy.EhcacheAccessStrategyFactoryImpl
3. HHH020007:readonlycacheconfiguredformutableentity
4. [com.jmdoudoux.test.hibernatecache.entity.Pays]

Pour le cache des relations, par dfaut l'implmentation d'EhCache utilise une rgion qui se nomme du nom pleinement qualifi de l'entit suivi du
caractre point et du nom de l'attribut de la relation.

Rsultat :

1. WARN
2. [main]:org.hibernate.cache.ehcache.AbstractEhcacheRegionFactory
3. HHH020003:Couldnotfindaspecificehcacheconfigurationforcachenamed
4. [com.jmdoudoux.test.hibernatecache.entity.Devise.pays];usingdefaults.

Dans l'exemple ci-dessus, la rgion du cache concernant la relation 1-N entre devise et pays n'est pas configure. Il suffit alors de dfinir une nouvelle
rgion dans la configuration d'EhCache pour viter l'utilisation de la configuration par dfaut.

Pour le cache des requtes, par dfaut Hibernate utilise deux rgions qui se nomment:

org.hibernate.cache.spi.UpdateTimestampsCache
org.hibernate.cache.internal.StandardQueryCache

Rsultat :

01. INFO[main]:org.hibernate.cache.spi.UpdateTimestampsCache
02. HHH000250:Startingupdatetimestampscacheatregion:
03. org.hibernate.cache.spi.UpdateTimestampsCache
04. WARN
05. [main]:org.hibernate.cache.ehcache.AbstractEhcacheRegionFactory
06. HHH020003:Couldnotfindaspecificehcacheconfigurationforcachenamed
07. [org.hibernate.cache.spi.UpdateTimestampsCache];usingdefaults.
08. INFO
09. [main]:org.hibernate.cache.internal.StandardQueryCacheHHH000248:
10. Startingquerycacheatregion:org.hibernate.cache.internal.StandardQueryCache
11. WARN
12. [main]:org.hibernate.cache.ehcache.AbstractEhcacheRegionFactory
13. HHH020003:Couldnotfindaspecificehcacheconfigurationforcachenamed
14. [org.hibernate.cache.internal.StandardQueryCache];usingdefaults.

Dans l'exemple ci-dessus, les deux rgions du cache concernant les requtes ne sont pas configures. Il suffit alors de dfinir deux nouvelles rgions
dans la configuration d'EhCache pour viter l'utilisation de la configuration par dfaut.

https://www.jmdoudoux.fr/java/dej/chaphibernate.htm 80/105
24/04/2017 DvelopponsenJavaHibernate
Le nom de la rgion utilise par Hibernate pour le cache des rsultats des requtes est org.hibernate.cache.StandardQueryCache.

Exemple :

1. <cachename="org.hibernate.cache.StandardQueryCache"
2. maxEntriesLocalHeap="50"eternal="false"timeToLiveSeconds="300"
3. overflowToDisk="true"/>

Le cache des requtes utilise aussi une autre rgion dont le nom est org.hibernate.cache.UpdateTimestampsCache. Cette rgion contient la date/heure
de dernire mise jour de chaque table. Pour le bon fonctionnement du cache des requtes, il est prfrable que cette rgion ne soit jamais invalide.

Exemple :

1. <cachename="org.hibernate.cache.UpdateTimestampsCache"
2. maxEntriesLocalHeap="500"eternal="true"overflowToDisk="true"/>

Il est possible de dfinir et d'utiliser une rgion ddie pour une ou plusieurs requtes. Le nom attribu dans la configuration de la rgion dans le
fichier ehcache.xml doit tre utilis comme paramtre de la mthode setCacheRegion() pour les requtes (Query ou Criteria) qui doivent tre mises en
cache. La valeur de l'attribut name n'est pas impose mais par convention elle commence par "query." et ce nom doit tre unique pour toutes les rgions.

Exemple :

1. <cachename="query.paysPourUneMonnaie"maxEntriesLocalHeap="20"
2. eternal="false"timeToLiveSeconds="3600"overflowToDisk="true"/>

Enfin, il faut ajouter les bibliothques requises pour EhCache dans le classpath. Celles-ci peuvent tre trouves dans le sous-rpertoire
lib/optional/ehcache.

54.12.4. Les stratgies d'usage transactionnel du cache

Une stratgie d'usage transactionnel permet de dterminer comment les lments vont tre obtenus et stocks dans le cache de second niveau et
comment les accs concurrents vont tre grs.

Hibernate propose le support de quatre stratgies transactionnelles pour le cache de second niveau:

read-only: utilisable pour des entits qui ne sont jamais mises jour.
read-write: utilisable pour des entits qui sont mises jour occasionnellement en utilisant la smantique du niveau d'isolation read committed.
Cette stratgie impose un lger surcot lors de son utilisation.
nonstrict-read-write: utilisable pour des entits qui sont mises jour occasionnellement. L'entit dans le cache n'est jamais verrouille. Si un
accs concurrent une entit est fait, cette stratgie ne garantit pas que ce qui est retourn du cache soit l'image des donnes
correspondantes dans la base de donnes. Elle ne propose donc aucune gestion des accs concurrents.
transactional : utilisable uniquement dans un environnement possdant un gestionnaire de transactions distribues respectant l'API JTA qui
permet d'utiliser la smantique du niveau d'isolation repeatable read.

Une stratgie d'usage transactionnel doit tre prcise pour chaque entit et collection configures pour tre mises dans le cache de second niveau.

54.12.4.1. La stratgie read-only

La stratgie read-only est utilisable sur des donnes qui ne seront utilises qu'en lecture seule et ne seront donc jamais mises jour. Elle convient
parfaitement des entits de type donnes de rfrence.

La mise en oeuvre de cette stratgie est la plus simple et la plus performante, de plus elle est utilisable en cluster.

Il est prfrable d'utiliser la stratgie read_only sur des entits dont l'attribut mutable possde la valeur false.

Remarque: l'utilisation de la stratgie read-only interdit les mises jour sur une entit mais elle n'interdit pas l'ajout de nouvelles entits.

54.12.4.2. La stratgie read-write

La stratgie read-write est utilisable sur des donnes qui pourront tre lues et/ou modifies sans requrir un niveau d'isolation transactionnelle de type
Serializable.

https://www.jmdoudoux.fr/java/dej/chaphibernate.htm 81/105
24/04/2017 DvelopponsenJavaHibernate
Les mises jour des entits mises en cache sont aussi faites dans le cache. Ces mises jour sont faites de manire concurrente grce la pose d'un
verrou. Cette stratgie est similaire au niveau d'isolation read committed.

Avec la stratgie read-write, ds qu'une entit est mise jour, un verrou est pos pour ses donnes dans le cache empchant leur accs par d'autres
sessions qui sont alors obliges de relire les donnes dans la base de donnes. Lorsque la transaction est valide, les donnes du cache sont rafraichies
et le verrou est retir.

Cette stratgie permet d'viter d'avoir des dirty read et permet aux sessions d'obtenir des donnes de manire read committed aussi bien de la base
de donnes que du cache.

Cette stratgie induit un lger surcot li au verrouillage des donnes dans le cache.

Il est important que la transaction soit termine avant l'invocation de la mthode close() ou de la mthode disconnect() de la session.

Cette stratgie ne doit pas tre utilise si le niveau d'isolation des transactions requis est Serializable.

Pour pouvoir tre utilis dans un cluster, l'implmentation du cache doit permettre de poser les verrous dans les diffrents noeuds du cluster. C'est par
exemple le cas du cache Coherence d'Oracle.

54.12.4.3. La stratgie nonstrict-read-write

La stratgie nonstrict_read_write est utilisable pour des donnes qui ne changent pas frquemment voire mme jamais. Elle ne vrifie pas que deux
transactions mettent jour des donnes qui sont dans le cache: aucun verrou n'est pos lors de ces modifications. Les accs concurrents sont donc
possibles mais cette stratgie ne garantit pas que les donnes retournes seront les plus fraiches et donc le reflet de ce qui est dans la base de
donnes.

Si l'application peut accepter que les donnes ne soient pas toujours consistantes et que les donnes ne soient frquemment modifies, l'utilisation de
la stratgie nonstrict-read-write la place de la stratgie read-write peut amliorer les performances.

La stratgie nonstrict-read-write retire les donnes du cache d'une entit mise jour lorsque la mthode flush() de la session est invoque.

La stratgie nonstrict-read-write ne pose jamais de verrou. Lorsque qu'un objet doit tre modifi, les anciennes valeurs restent dans le cache jusqu'
ce que la transaction soit valide par un commit. Si une autre session veut accder l'objet, elle obtiendra les donnes du cache (dirty read). Ds que la
transaction est valide, les donnes de l'entit sont supprimes du cache : lorsqu'une session voudra obtenir les donnes de l'entit, elle sera donc
forcer de relire les donnes de la base de donnes et de les insrer dans le cache.

La stratgie nonstrict-read-write est donc utilisable si l'application peut supporter des dirty reads qui peuvent arriver lorsque les donnes sont
rpercutes dans la base de donnes sans tre encore retires du cache.

Avec la stratgie nonstrict-read-write, il est prfrable de configurer l'invalidation priodique de la rgion afin de permettre d'amliorer la fracheur
des donnes.

54.12.4.4. La stratgie transactional

La stratgie transactional doit tre utilise dans un environnement utilisant un gestionnaire de transactions distribues de type JTA.

Cette stratgie n'est utilisable qu'avec un cache transactionnel comme JBoss TreeCache.

Avec les stratgies nonstrict-read-write et read-write, le cache est mis jour de manire asynchrone une fois que la transaction est valide. Avec la
stratgie transactional, le cache est mis jour en mme temps que la transaction est valide.

Il faut prciser Hibernate le nom d'une classe qui sera instancie pour lui permettre d'obtenir le gestionnaire de transactions du conteneur dans
lequel l'application s'excute. La valeur de cette proprit est donc dpendante de l'environnement d'excution.

Comme l'accs au TransactionManager de JTA n'est pas standardis, cette classe permet d'obtenir l'instance de l'environnement d'excution
correspondant.

Jusqu' la version 3.6 incluse, la classe utiliser doit implmenter l'interface TransactionManagerLookup. Il faut fournir son nom pleinement qualifi
la proprit hibernate.transaction.manager_lookup_class.

Conteneur Proprit hibernate.transaction.manager_lookup_class

Oracle OAS org.hibernate.transaction.OC4JtransactionManagerLookup

JBoss AS org.hibernate.transaction.JbossTransactionManagerLookup

JBoss Transactions org.hibernate.transaction.JbossTSStandaloneTransactionManagerLookup

GlassFish org.hibernate.transaction.SunONETransactionManagerLookup

JOTM org.hibernate.transaction.JOTMTransactionManagerLookup

IBM Websphere AS 4 5.1 org.hibernate.transaction.WebSphereTransactionManagerLookup

IBM Websphere AS 6 et suprieur org.transaction.WebSphereExtendedJTATransactionLookup

Atomikos com.atomikos.icatch.jta.hibernate3.TransactionManagerLookup

https://www.jmdoudoux.fr/java/dej/chaphibernate.htm 82/105
24/04/2017 DvelopponsenJavaHibernate

Resin org.hibernate.transaction.ResinTransactionManagerLookup

Orion org.hibernate.transaction.OrionTransactionManagerLookup

Oracle Weblogic org.hibernate.transaction.WeblogicTransactionManagerLookup

Infinispan org.infinispan.transaction.lookup.JBossStandaloneJTAManagerLookup

Apache Tomee org.apache.openejb.hibernate.TransactionManagerLookup

JonAs org.hibernate.transaction.JOnASTransactionManagerLookup

Jrun4 org.hibernate.transaction.JRun4TransactionManagerLookup

A partir de la version 4.0 d'Hibernate, il faut utiliser le service de type JtaPlatform.

Il faut utiliser la proprit hibernate.transaction.jta.platform et lui passer en paramtre le nom pleinement qualifi d'une classe qui implmente
l'interface org.hibernate.service.jta.platform.spi.JtaPlatform.

Conteneur Proprit hibernate.transaction.jta.platform

Bitronix org.hibernate.service.jta.platform.internal.BitronixJtaPlatform

Borland Enterprise Server org.hibernate.service.jta.platform.internal.BorlandEnterpriseServerJtaPlatform

JBoss AS org.hibernate.service.jta.platform.internal.JBossAppServerJtaPlatform

JBoss TM org.hibernate.service.jta.platform.internal.JBossStandAloneJtaPlatform

JonAs org.hibernate.service.jta.platform.internal.JOnASJtaPlatform

JOTM org.hibernate.service.jta.platform.internal.JOTMJtaPlatform

JRun 4 AS org.hibernate.service.jta.platform.internal.JRun4JtaPlatform

Aucun org.hibernate.service.jta.platform.internal.NoJtaPlatform

Oracle OC4J org.hibernate.service.jta.platform.internal.OC4JJtaPlatform

Orion AS org.hibernate.service.jta.platform.internal.OrionJtaPlatform

Resin AS org.hibernate.service.jta.platform.internal.ResinJtaPlatform

Oracle Glassfish org.hibernate.service.jta.platform.internal.SunOneJtaPlatform

Pont vers TransactionManagerLookup org.hibernate.service.jta.platform.internal.TransactionManagerLookupBridge

Oracle Weblogic org.hibernate.service.jta.platform.internal.WeblogicJtaPlatform

IBM Websphere 6 et suprieur org.hibernate.service.jta.platform.internal.WebSphereExtendedJtaPlatform

IBM Websphere 4 5.1 org.hibernate.service.jta.platform.internal.WebSphereJtaPlatform

Exemple :

1. <propertyname="hibernate.transaction.jta.platform"
2. value="org.hibernate.service.jta.platform.internal.SunOneJtaPlatform"/>

L'utilisation de l'API TransactionManagerLookup affiche une entre de type warning dans le journal.

Rsultat :

1. HHH000427:
2. Usingdeprecatedorg.hibernate.transaction.TransactionManagerLookupstrategy
3. [hibernate.transaction.manager_lookup_class],usenewer
4. org.hibernate.service.jta.platform.spi.JtaPlatformstrategyinstead
5. [hibernate.transaction.jta.platform]

54.12.4.5. Le support des stratgies par les diffrents caches

Les caches supports en standard par Hibernate proposent le support d'une ou plusieurs stratgies.

nonstrict-read-write
read-only read-write transactional
Cache (lecture-criture non
(lecture seule) (lecture-criture) (transactionnel)
stricte)

Hashtable (ne pas utiliser en


oui oui oui
production)

https://www.jmdoudoux.fr/java/dej/chaphibernate.htm 83/105
24/04/2017 DvelopponsenJavaHibernate

nonstrict-read-write
read-only read-write transactional
Cache (lecture-criture non
(lecture seule) (lecture-criture) (transactionnel)
stricte)

oui (depuis la version 2.1


EHCache oui oui oui
d'EhCache)

OSCache oui oui oui

SwarmCache oui oui

JBoss TreeCache 1.x oui oui

JBoss TreeCache 2 oui oui

54.12.5. Le cache des entits

Le cache des entits est utilis lors de la lecture d'entits de la base de donnes partir de leur identifiant (par exemple en utilisant les mthodes
Session.get() ou Session.load()) et lors du parcours des relations de type OneToOne ou ManyToOne.

Par dfaut, Hibernate utilise pour une entit une rgion dont le nom est le nom pleinement qualifi de la classe de l'entit. Si aucune rgion possdant
ce nom n'est dfinie alors c'est la rgion par dfaut qui est utilise.

Hibernate ne stocke pas directement les instances des entits lues de la base de donnes dans le cache mais une copie srialise: ceci permet d'viter
des problmes d'accs concurrents si plusieurs transactions font rfrence au mme objet.

Les identifiants des entits sont utiliss comme index dans le cache.

Exemple :

01. packagecom.jmdoudoux.test.hibernatecache;
02.
03. importjava.util.Set;
04. importorg.hibernate.Session;
05. importorg.hibernate.SessionFactory;
06. importorg.hibernate.Transaction;
07. importorg.hibernate.cfg.Configuration;
08. importcom.jmdoudoux.test.hibernatecache.entity.Devise;
09. importcom.jmdoudoux.test.hibernatecache.entity.Pays;
10.
11. publicclassTestHibernateCache{
12. privatestaticSessionFactorysessionFactory=null;
13. publicstaticvoidmain(String[]args){
14. try{
15. sessionFactory=newConfiguration().configure().buildSessionFactory();
16. for(inti=0;i<3;i++){
17. lirePays();
18. }
19. }catch(Throwableex){
20. System.err.println("Erreurdurantlestraitements"+ex);
21. }finally{
22. sessionFactory.close();
23. }
24. }
25.
26. publicstaticvoidlirePays()throwsException{
27. Sessionsession=sessionFactory.openSession();
28. Transactiontx=null;
29. try{
30. tx=session.beginTransaction();
31. Payspays=(Pays)session.load(Pays.class,newInteger(4));
32. System.out.println("pays:id="+pays.getId()+"codeIso="
33. +pays.getCodeIso()+"nom="+pays.getNom());
34. tx.commit();
35. }catch(Exceptione){
36. if(tx!=null){
37. tx.rollback();
38. }
39. throwe;
40. }finally{
41. session.close();
42. }
43. }
44. }

Rsultat :

01. Hibernate:selectpays0_.idasid0_0_,pays0_.code_isoas
02. code2_0_0_,pays0_.nomasnom0_0_,pays0_.FK_DEVISEasFK4_0_0_frompays
03. pays0_wherepays0_.id=?
04. pays:id=4codeIso=LUnom=Luxembourg
05. Hibernate:selectpays0_.idasid0_0_,pays0_.code_isoas
06. code2_0_0_,pays0_.nomasnom0_0_,pays0_.FK_DEVISEasFK4_0_0_frompays

07. pays0_wherepays0_.id=?
https://www.jmdoudoux.fr/java/dej/chaphibernate.htm 84/105
24/04/2017 DvelopponsenJavaHibernate
07. pays0_wherepays0_.id=?
08. pays:id=4codeIso=LUnom=Luxembourg
09. Hibernate:selectpays0_.idasid0_0_,pays0_.code_isoas
10. code2_0_0_,pays0_.nomasnom0_0_,pays0_.FK_DEVISEasFK4_0_0_frompays
11. pays0_wherepays0_.id=?
12. pays:id=4codeIso=LUnom=Luxembourg

Par dfaut, aucune entit n'est mise dans le cache de second niveau qui a t activ et configur.

Chaque entit concerne doit tre configure pour tre stocke dans le cache de second niveau. Cette configuration doit permettre de prciser la
stratgie de gestion des accs concurrents aux donnes des entits.

Il existe plusieurs manires de dclarer qu'une entit doit tre mise dans le cache de second niveau:

utiliser le tag <cache> dans le fichier de mapping hbm.xml


utiliser l'annotation @Cache sur la classe de l'entit
utiliser le tag <class-cache> dans le fichier de configuration d'Hibernate

Dans le fichier de mapping, la dfinition de la mise en cache pour une entit se fait en utilisant le tag <cache>.

Exemple :

1. <cacheusage="transactional|readwrite|nonstrictreadwrite|readonly"
2. region="nom_de_la_region"include="all|nonlazy"/>

L'attribut obligatoire usage permet de prciser la stratgie de concurrence d'accs transactionnel qui sera applique avec l'entit dans le cache.

L'attribut optionnel region permet de prciser le nom de la rgion utiliser dans le cache. Par dfaut, c'est le nom pleinement qualifi de la classe de
l'entit.

L'attribut optionnel include peut prendre deux valeurs: all et non-lazy. La valeur non-lazy permet de ne pas mettre en cache des entits charges de
manire lazy. La valeur par dfaut est all.

Exemple :

01. <?xmlversion="1.0"encoding="UTF8"?>
02. <!DOCTYPEhibernatemappingPUBLIC"//Hibernate/Hibernate
03. MappingDTD//EN"
04. "http://hibernate.org/dtd/hibernatemapping3.0.dtd">
05.
06. <hibernatemapping>
07. <classname="com.jmdoudoux.test.hibernatecache.entity.Pays"table="pays">
08. <cacheusage="readonly"/>
09. <idname="id"column="id"type="int">
10. <generatorclass="identity"/>
11. </id>
12. <propertyname="codeIso"column="code_iso"notnull="true"type="string"/>
13. <propertyname="nom"notnull="true"type="string"/>
14. <manytoonename="devise"column="FK_DEVISE"
15. class="com.jmdoudoux.test.hibernatecache.entity.Devise"/>
16. </class>
17. </hibernatemapping>

L'utilisation du cache de second niveau doit tre active et configure comme indiqu dans la section concerne.

Rsultat :

1. Hibernate:selectpays0_.idasid0_0_,pays0_.code_isoas
2. code2_0_0_,pays0_.nomasnom0_0_,pays0_.FK_DEVISEasFK4_0_0_frompays
3. pays0_wherepays0_.id=?
4. pays:id=4codeIso=LUnom=Luxembourg
5. pays:id=4codeIso=LUnom=Luxembourg
6. pays:id=4codeIso=LUnom=Luxembourg

La requte n'est plus effectue qu'une seule fois sur la base de donnes: pour les autres accs, les donnes de l'entit sont extraites du cache.

Dans la classe de l'entit, il est possible d'utiliser le tag @org.hibernate.annotations.Cache.

Exemple :

01. packagecom.jmdoudoux.test.hibernatecache.entity;
02.
03. importjava.io.Serializable;
04. importjavax.persistence.Basic;
05. importjavax.persistence.CascadeType;
06. importjavax.persistence.Column;
07. importjavax.persistence.Entity;
08. importjavax.persistence.Id;
09. importjavax.persistence.JoinColumn;
https://www.jmdoudoux.fr/java/dej/chaphibernate.htm 85/105
24/04/2017 DvelopponsenJavaHibernate
09. importjavax.persistence.JoinColumn;
10. importjavax.persistence.ManyToOne;
11. importjavax.persistence.Table;
12. importorg.hibernate.annotations.Cache;
13. importorg.hibernate.annotations.CacheConcurrencyStrategy;
14.
15. @Entity
16. @Table(name="PAYS")
17. @Cache(usage=CacheConcurrencyStrategy.READ_WRITE)
18. publicclassPaysimplementsSerializable{
19. privatestaticfinallongserialVersionUID=1L;
20.
21. @Id
22. privateintid;
23.
24. @Column(name="code_iso")
25. privateStringcodeIso;
26.
27. @Basic
28. privateStringnom;
29.
30. @ManyToOne(cascade={CascadeType.PERSIST,CascadeType.MERGE})
31. @JoinColumn(name="FK_DEVISE")
32. privateDevisedevise;
33.
34. publicPays(){
35. }
36.
37. //gettersetsetters
38.
39. @Override
40. publicStringtoString(){
41. return"Pays[id="+id+",codeIso="+codeIso+",nom="+nom
42. +",devise="+devise+",getClass()="+getClass()+",hashCode()="
43. +hashCode()+",toString()="+super.toString()+"]";
44. }
45. }

L'attribut obligatoire usage permet de prciser la stratgie de gestion des accs concurrents grce l'numration
org.hibernate.annotations.CacheConcurrencyStrategy qui possde les valeurs NONE, READ_ONLY, READ_WRITE, NONSTRICT_READ_ONLY et
TRANSACTIONAL.

L'attribut optionnel region permet de prciser le nom de la rgion du cache utiliser. Par dfaut, c'est le nom pleinement qualifi de la classe de
l'entit.

L'attribut optionnel include peut prendre deux valeurs : all pour inclure toutes les proprits ou non-lazy pour inclure uniquement les proprits
charges de manire diffre.

Enfin, avec le fichier de configuration hibernate.cfg.xml, il est possible d'utiliser le tag <class-cache> pour les entits.

Le tag <class-cache> possde deux attributs:

class: permet de prciser le nom pleinement qualifi de la classe de l'entit


usage: permet de prciser la stratgie de gestion des accs concurrents

Exemple :

01. <?xmlversion='1.0'encoding='utf8'?>
02. <!DOCTYPEhibernateconfigurationSYSTEM
03. "http://hibernate.org/dtd/hibernateconfiguration3.0.dtd">
04. <hibernateconfiguration>
05. <sessionfactory>
06. <!Databaseconnectionsettings>
07. <propertyname="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
08. <propertyname="hibernate.connection.url">jdbc:mysql://localhost:3306/mabdd</property>
09. <propertyname="hibernate.connection.username">root</property>
10. <propertyname="hibernate.connection.password"></property>
11. <propertyname="hibernate.connection.pool_size">1</property>
12. <propertyname="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>
13. <propertyname="hibernate.current_session_context_class">thread</property>
14. <!Cachedesecondniveaudsactiv>
15. <!propertyname="hibernate.cache.provider_class">
16. org.hibernate.cache.internal.NoCacheProvider</property>
17. <propertyname="hibernate.cache.region.factory_class">
18. org.hibernate.cache.ehcache.SingletonEhCacheRegionFactory</property>
19. <propertyname="hibernate.generate_statistics">true</property>
20. <propertyname="hibernate.cache.use_structured_entries">true</property>
21. <!AfficherlesrequtesSQLexcutessurlasortiestandard>
22. <propertyname="hibernate.show_sql">true</property>
23. <mappingresource="Pays.hbm.xml"/>
24. <mappingresource="Devise.hbm.xml"/>
25. <classcacheclass="com.jmdoudoux.test.hibernatecache.entity.Pays"usage="readonly"/>
26. </sessionfactory>
27. </hibernateconfiguration>

Les mthodes load() et get() vrifient toujours le cache avant d'excuter une requte sur la base de donnes.

https://www.jmdoudoux.fr/java/dej/chaphibernate.htm 86/105
24/04/2017 DvelopponsenJavaHibernate
Le cache de second niveau ne stocke pas une instance d'une entit mais une forme dite dshydrate (dehydrated) d'une entit: ce sont les valeurs de
chaque proprit qui sont stockes dans le cache. Si cette proprit est du type d'une entit (dans une association de type xxx-to-one), alors c'est
l'identifiant de cette entit qui est stock dans le cache.

Seules les donnes de l'entit elle-mme sont mises en cache: les entits de ses associations ne sont pas mises dans le cache par dfaut sauf si les
entits correspondantes sont explicitement configures pour y tre places.

A chaque fois qu'une instance de l'entit doit tre obtenue du cache, une nouvelle instance est cre partir des valeurs des proprits stockes dans
le cache.

Il est donc trs important de tenir compte du fait que si de nombreuses entits sont obtenues du cache de second niveau alors il y a un surcot li
chaque fois la cration d'une nouvelle instance.

Le cache de second niveau ne contient pas de graphe d'objets: les relations ne contiennent que les identifiants des entits. Ceci permet Hibernate de
ne pas rpliquer de donnes.

Une exception de type java.lang.UnsupportedOperationException avec le message Can't write to a readonly object est leve si une modification est
faite sur une entit dont la stratgie de cache est read-only.

Si une entit stocke en cache doit tre mise jour, il faut configurer sa mise en cache en utilisant une stratgie le permettant. Par exemple, la
stratgie read-write permet de mettre jour les donnes de l'entit mise en cache.

Exemple :

01. publicstaticvoidlireEtModifierPays()throwsException{
02. Sessionsession1=sessionFactory.openSession();
03. Sessionsession2=null;
04. Transactiontx=null;
05. try{
06. tx=session1.beginTransaction();
07. Payspays=(Pays)session1.load(Pays.class,newInteger(99));
08. System.out.println("session1pays:id="+pays.getId()+"codeIso="
09. +pays.getCodeIso()+"nom="+pays.getNom());
10. pays.setNom(pays.getNom()+"modifie");
11. tx.commit();
12. session2=sessionFactory.openSession();
13. tx=session2.beginTransaction();
14. pays=(Pays)session2.load(Pays.class,newInteger(99));
15. System.out.println("session2pays:id="+pays.getId()+"codeIso="
16. +pays.getCodeIso()+"nom="+pays.getNom());
17. tx.commit();
18. }catch(Exceptione){
19. if(tx!=null){
20. tx.rollback();
21. }
22. throwe;
23. }finally{
24. if(session2!=null)
25. session2.close();
26. if(session1!=null)
27. session1.close();
28. }
29. }

Rsultat :

01. Hibernate:selectpays0_.idas
02. id0_0_,pays0_.code_isoascode2_0_0_,pays0_.nomasnom0_0_,pays0_.FK_DEVISE
03. asFK4_0_0_frompayspays0_wherepays0_.id=?
04. session1pays:id=99codeIso=XXXnom=test
05. Hibernate:updatepaysset
06. code_iso=?,nom=?,FK_DEVISE=?whereid=?
07. session2pays:id=99codeIso=XXXnom=testmodifie
08. 2012082822:40:01.982INFO
09. [main]:org.hibernate.stat.internal.ConcurrentStatisticsImplHHH000239:
10. Secondlevelcacheputs:2
11. 2012082822:40:01.998INFO
12. [main]:org.hibernate.stat.internal.ConcurrentStatisticsImplHHH000237:
13. Secondlevelcachehits:1
14. 2012082822:40:01.998
15. INFO
16. [main]:org.hibernate.stat.internal.ConcurrentStatisticsImplHHH000238:
17. Secondlevelcachemisses:1

Dans l'exemple ci-dessus, l'entit est mise deux fois dans le cache de second niveau: une premire fois aprs la lecture et une seconde fois aprs la
mise jour de l'entit. Lorsque l'entit est relue dans la seconde session, l'entit est obtenue du cache de second niveau des entits.

Cet exemple fonctionne comme attendu car les deux sessions ne sont pas imbriques.

Exemple :

01. publicstaticvoidlireEtModifierPays()throwsException{
02. Sessionsession1=sessionFactory.openSession();
03. Sessionsession2=sessionFactory.openSession();
04. Transactiontx=null;
05. try{
https://www.jmdoudoux.fr/java/dej/chaphibernate.htm 87/105
24/04/2017 DvelopponsenJavaHibernate
05. try{
06. tx=session1.beginTransaction();
07. Payspays=(Pays)session1.load(Pays.class,newInteger(99));
08. System.out.println("session1pays:id="+pays.getId()+"codeIso="
09. +pays.getCodeIso()+"nom="+pays.getNom());
10. pays.setNom(pays.getNom()+"modifie");
11. tx.commit();
12. tx=session2.beginTransaction();
13. pays=(Pays)session2.load(Pays.class,newInteger(99));
14. System.out.println("session2pays:id="+pays.getId()+"codeIso="
15. +pays.getCodeIso()+"nom="+pays.getNom());
16. tx.commit();
17. }catch(Exceptione){
18. if(tx!=null){
19. tx.rollback();
20. }
21. throwe;
22. }finally{
23. if(session2!=null)
24. session2.close();
25. if(session1!=null)
26. session1.close();
27. }
28. }

Rsultat :

01. Hibernate:selectpays0_.idas
02. id0_0_,pays0_.code_isoascode2_0_0_,pays0_.nomasnom0_0_,pays0_.FK_DEVISE
03. asFK4_0_0_frompayspays0_wherepays0_.id=?
04. 2012081921:55:51.721INFO
05. session1pays:id=99codeIso=XXXnom=testmodifie
06. Hibernate:updatepaysset
07. code_iso=?,nom=?,FK_DEVISE=?whereid=?
08. Hibernate:selectpays0_.idas
09. id0_0_,pays0_.code_isoascode2_0_0_,pays0_.nomasnom0_0_,pays0_.FK_DEVISE
10. asFK4_0_0_frompayspays0_wherepays0_.id=?
11. session2pays:id=99codeIso=XXXnom=testmodifiemodifie

Dans l'exemple ci-dessus, l'entit est mise deux fois dans le cache de second niveau: une premire fois aprs la lecture et une seconde fois aprs la
mise jour de l'entit. Lorsque l'entit est relue dans la seconde session, l'entit n'est pas obtenue du cache de second niveau des entits mais elle est
relue de la base de donnes.

Hibernate vrifie que la date de cration de la session est suprieure la date de mise en cache de l'entit: si ce n'est pas le cas, la donne est relue
de la base de donnes.

Dans l'exemple ci-dessus, l'entit est mise deux fois dans le cache de second niveau mais elle n'est jamais obtenue du cache, ce qui est contraire ce
qui pourrait tre voulu.

La stratgie nonstrict-read-write permet aussi de mettre jour un entit mise en cache mais les donnes du cache ne sont pas modifies: les donnes
de l'entit son simplement invalides dans le cache, ce qui reforce une lecture pour le prochain accs l'entit.

Rsultat :

01. Hibernate:selectpays0_.idas
02. id0_0_,pays0_.code_isoascode2_0_0_,pays0_.nomasnom0_0_,pays0_.FK_DEVISE
03. asFK4_0_0_frompayspays0_wherepays0_.id=?
04. session1pays:id=99codeIso=XXXtestnom=testmodifie
05. Hibernate:updatepaysset
06. code_iso=?,nom=?,FK_DEVISE=?whereid=?
07. Hibernate:selectpays0_.idas
08. id0_0_,pays0_.code_isoascode2_0_0_,pays0_.nomasnom0_0_,pays0_.FK_DEVISE
09. asFK4_0_0_frompayspays0_wherepays0_.id=?
10. session2pays:id=99codeIso=XXXtestnom=testmodifie
11. 2012082822:43:53.960INFO[main]:org.hibernate.stat.internal.ConcurrentStatisticsImpl
12. HHH000239:Secondlevelcacheputs:2
13. 2012082822:43:53.960INFO
14. [main]:org.hibernate.stat.internal.ConcurrentStatisticsImplHHH000237:
15. Secondlevelcachehits:0
16. 2012082822:43:53.960
17. INFO[main]:org.hibernate.stat.internal.ConcurrentStatisticsImpl
18. HHH000238:Secondlevelcachemisses:2

54.12.6. Le cache des associations many

Le cache des associations est utilis lors du parcours des relations de type xxxToMany.

Par dfaut, les associations ne sont pas mises dans le cache de second niveau par Hibernate. Hibernate laisse la possibilit de choisir les associations qui
doivent tre mises en cache ou tre systmatiquement relues de la base de donnes. Celles qui doivent donc tre mises en cache doivent tre
configures comme telles.

https://www.jmdoudoux.fr/java/dej/chaphibernate.htm 88/105
24/04/2017 DvelopponsenJavaHibernate
L'exemple de cette section va afficher la liste des pays de la base de donnes qui utilisent l'euro, trois fois de suite. Cette opration va exploiter la
relation 1-N entre devise et pays.

Exemple :

01. packagecom.jmdoudoux.test.hibernatecache;
02.
03. importjava.util.Set;
04. importorg.hibernate.Session;
05. importorg.hibernate.SessionFactory;
06. importorg.hibernate.Transaction;
07. importorg.hibernate.cfg.Configuration;
08. importcom.jmdoudoux.test.hibernatecache.entity.Devise;
09. importcom.jmdoudoux.test.hibernatecache.entity.Pays;
10.
11. publicclassTestHibernateCache{
12. privatestaticSessionFactorysessionFactory=null;
13. publicstaticvoidmain(String[]args){
14. try{
15. sessionFactory=newConfiguration().configure().buildSessionFactory();
16. for(inti=0;i<3;i++){
17. //lirePays();
18. listerPaysEuro();
19. }
20. }catch(Throwableex){
21. System.err.println("Erreurdurantlestraitements"+ex);
22. }finally{
23. sessionFactory.close();
24. }
25. }
26.
27. publicstaticvoidlisterPaysEuro()throwsException{
28. Sessionsession=sessionFactory.openSession();
29. Transactiontx=null;
30. try{
31. tx=session.beginTransaction();
32. DevisedeviseEur=(Devise)session.load(Devise.class,newInteger(1));
33. System.out.println("Devise:id="+deviseEur.getId()+"code="
34. +deviseEur.getCode()+"libelle="+deviseEur.getLibelle());
35. Set<Pays>paysEur=deviseEur.getPays();
36. for(Payspays:paysEur){
37. System.out.println("pays:id="+pays.getId()+"codeIso="
38. +pays.getCodeIso()+"nom="+pays.getNom());
39. }
40. tx.commit();
41. }catch(Exceptione){
42. if(tx!=null){
43. tx.rollback();
44. }
45. throwe;
46. }finally{
47. session.close();
48. }
49. }
50. }

Rsultat :

01. Hibernate:selectdevise0_.IDasID1_0_,devise0_.CODEas
02. CODE1_0_,devise0_.LIBELLEasLIBELLE1_0_fromDEVISEdevise0_where
03. devise0_.ID=?
04. Devise:id=1code=EURlibelle=Euro
05. Hibernate:selectpays0_.FK_DEVISEasFK4_1_1_,pays0_.idasid1_,
06. pays0_.idasid0_0_,pays0_.code_isoascode2_0_0_,pays0_.nomasnom0_0_,
07. pays0_.FK_DEVISEasFK4_0_0_frompayspays0_wherepays0_.FK_DEVISE=?
08. pays:id=4codeIso=LUnom=Luxembourg
09. pays:id=3codeIso=Inom=Italie
10. pays:id=2codeIso=Dnom=Allemagne
11. pays:id=1codeIso=FRnom=France
12. Hibernate:selectdevise0_.IDasID1_0_,devise0_.CODEas
13. CODE1_0_,devise0_.LIBELLEasLIBELLE1_0_fromDEVISEdevise0_where
14. devise0_.ID=?
15. Devise:id=1code=EURlibelle=Euro
16. Hibernate:selectpays0_.FK_DEVISEasFK4_1_1_,pays0_.idasid1_,
17. pays0_.idasid0_0_,pays0_.code_isoascode2_0_0_,pays0_.nomasnom0_0_,
18. pays0_.FK_DEVISEasFK4_0_0_frompayspays0_wherepays0_.FK_DEVISE=?
19. pays:id=2codeIso=Dnom=Allemagne
20. pays:id=3codeIso=Inom=Italie
21. pays:id=4codeIso=LUnom=Luxembourg
22. pays:id=1codeIso=FRnom=France
23. Hibernate:selectdevise0_.IDasID1_0_,devise0_.CODEas
24. CODE1_0_,devise0_.LIBELLEasLIBELLE1_0_fromDEVISEdevise0_where
25. devise0_.ID=?
26. Devise:id=1code=EURlibelle=Euro
27. Hibernate:selectpays0_.FK_DEVISEasFK4_1_1_,pays0_.idasid1_,
28. pays0_.idasid0_0_,pays0_.code_isoascode2_0_0_,pays0_.nomasnom0_0_,
29. pays0_.FK_DEVISEasFK4_0_0_frompayspays0_wherepays0_.FK_DEVISE=?
30. pays:id=2codeIso=Dnom=Allemagne
31. pays:id=1codeIso=FRnom=France
32. pays:id=4codeIso=LUnom=Luxembourg
33. pays:id=3codeIso=Inom=Italie

https://www.jmdoudoux.fr/java/dej/chaphibernate.htm 89/105
24/04/2017 DvelopponsenJavaHibernate

A chaque itration, la devise est lue dans la base de donnes et une requte est effectue sur la base de donnes pour obtenir les pays possdant cette
devise.

Pour limiter le nombre de requtes effectues sur la base de donnes, il est possible d'utiliser le cache des associations.

Lors du parcours des lments de l'association, Hibernate stocke dans le cache les identifiants des entits mais pas les entits elles-mmes. Si une
entit associe est configure pour tre mise en cache, alors les donnes de l'entit sont retrouves dans le cache, sinon elle sera relue de la base de
donnes.

Le cache des associations ne stockent que des identifiants: pour l'entit et pour ses entits associes. De ce fait, si le cache d'associations est activ
alors il est important d'activit aussi le cache sur les entits correspondantes pour viter de grer des requtes inutiles sur la base de donnes.

Par dfaut, aucune association n'est mise dans le cache de second niveau qui a t activ et configur. Chaque association concerne doit tre
configure pour tre stocke dans le cache de second niveau. Cette configuration doit permettre de prciser la stratgie de gestion des accs
concurrents aux donnes des associations.

Il existe plusieurs manires de dclarer qu'une association doit tre mise dans le cache de second niveau:

utiliser le tag <cache> dans le fichier de mapping hbm.xml


utiliser l'annotation @Cache sur la collection dans la classe de l'entit
utiliser le tag <collection-cache> dans le fichier de configuration d'Hibernate

Une seule de ces solutions doit tre utilise.

Dans le fichier de mapping, la dfinition de la mise en cache de l'association se fait en utilisant le tag <cache>

Exemple :

01. <classname="Devise"table="DEVISE">
02. <cacheusage="readonly"/>
03. <idname="id"column="ID">
04. <generatorclass="identity"/>
05. </id>
06. <propertyname="code"column="CODE"/>
07. <propertyname="libelle"column="LIBELLE"/>
08. <setname="pays">
09. <cacheusage="readonly"/>
10. <keycolumn="FK_DEVISE"/>
11. <onetomanyclass="Pays"/>
12. </set>
13. </class>

Attention: il est ncessaire que le cache pour les entits des deux relations soit actif puisque le cache des associations ne stocke que les identifiants
des entits. Ceci vitera Hibernate de refaire une lecture pour chacune des entits car il pourra directement obtenir les entits du cache.

Exemple :

01. <?xmlversion="1.0"encoding="UTF8"?>
02. <!DOCTYPEhibernatemappingPUBLIC"//Hibernate/Hibernate
03. MappingDTD//EN""http://hibernate.org/dtd/hibernatemapping3.0.dtd">
04.
05. <hibernatemapping>
06. <classname="com.jmdoudoux.test.hibernatecache.entity.Pays"
07. table="pays">
08. <cacheusage="readonly"/>
09. <idname="id"column="id"type="int">
10. <generatorclass="identity"/>
11. </id>
12. <propertyname="codeIso"column="code_iso"
13. notnull="true"type="string"/>
14. <propertyname="nom"notnull="true"type="string"/>
15. <manytoonename="devise"column="FK_DEVISE"
16. class="com.jmdoudoux.test.hibernatecache.entity.Devise"/>
17. </class>
18. </hibernatemapping>

Dans le fichier de configuration hibernate.cfg.xml, il est possible d'utiliser le tag <collection-cache> pour les associations.

Le tag <collection-cache> possde deux attributs:

collection: permet de prciser le nom de la collection


usage: permet de prciser la stratgie de gestion des accs concurrents

Exemple :

01. <?xmlversion='1.0'encoding='utf8'?>
02. <!DOCTYPEhibernateconfigurationSYSTEM
03. "http://hibernate.org/dtd/hibernateconfiguration3.0.dtd">
04. <hibernateconfiguration>
05. <sessionfactory>
06. <!Databaseconnectionsettings>
07. <propertyname="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
https://www.jmdoudoux.fr/java/dej/chaphibernate.htm 90/105
24/04/2017 DvelopponsenJavaHibernate
07. <propertyname="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
08. <propertyname="hibernate.connection.url">jdbc:mysql://localhost:3306/mabdd</property>
09. <propertyname="hibernate.connection.username">root</property>
10. <propertyname="hibernate.connection.password"></property>
11. <propertyname="hibernate.connection.pool_size">1</property>
12. <propertyname="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>
13. <propertyname="hibernate.current_session_context_class">thread</property>
14. <!Cachedesecondniveaudsactiv>
15. <!propertyname="hibernate.cache.provider_class">
16. org.hibernate.cache.internal.NoCacheProvider</property>
17. <propertyname="hibernate.cache.region.factory_class">
18. org.hibernate.cache.ehcache.SingletonEhCacheRegionFactory</property>
19. <propertyname="hibernate.generate_statistics">true</property>
20. <propertyname="hibernate.cache.use_structured_entries">true</property>
21. <!AfficherlesrequtesSQLexcutessurlasortiestandard>
22. <propertyname="hibernate.show_sql">true</property>
23. <mappingresource="Pays.hbm.xml"/>
24. <mappingresource="Devise.hbm.xml"/>
25. <classcacheclass="com.jmdoudoux.test.hibernatecache.entity.Pays"usage="readonly"/>
26. <classcacheclass="com.jmdoudoux.test.hibernatecache.entity.Devise"usage="readonly"/>
27. <collectioncachecollection="com.jmdoudoux.test.hibernatecache.entity.Devise.pays"
28. usage="readonly"/>
29. </sessionfactory>
30. </hibernateconfiguration>

Pour mettre en cache les donnes d'une relation OneToMany ou ManyToMany, il est possible d'utiliser l'annotation @Cache.

Exemple :

01. packagecom.jmdoudoux.test.hibernatecache.entity;
02.
03. importjava.io.Serializable;
04. importjava.util.Set;
05. importjavax.persistence.Basic;
06. importjavax.persistence.Entity;
07. importjavax.persistence.Id;
08. importjavax.persistence.OneToMany;
09. importjavax.persistence.Table;
10. importorg.hibernate.annotations.Cache;
11. importorg.hibernate.annotations.CacheConcurrencyStrategy;
12.
13. @Entity
14. @Table(name="DEVISE")
15. @Cache(usage=CacheConcurrencyStrategy.READ_ONLY)
16. publicclassDeviseimplementsSerializable{
17. privatestaticfinallongserialVersionUID=1L;
18.
19. @Id
20. privateintid;
21.
22. @Basic
23. privateStringcode;
24.
25. @Basic
26. privateStringlibelle;
27.
28. @OneToMany(mappedBy="devise")
29. @Cache(usage=CacheConcurrencyStrategy.READ_ONLY)
30. privateSet<Pays>pays;
31.
32. publicDevise(){
33. }
34.
35. //gettersetsetters
36. }

L'utilisation du cache de second niveau doit tre active et configure comme indiqu dans la section concerne.

Rsultat :

01. Hibernate:selectdevise0_.IDasID1_0_,devise0_.CODEasCODE1_0_,
02. devise0_.LIBELLEasLIBELLE1_0_fromDEVISEdevise0_wheredevise0_.ID=?
03. Devise:id=1code=EURlibelle=Euro
04. Hibernate:selectpays0_.FK_DEVISEasFK4_1_1_,pays0_.idasid1_,
05. pays0_.idasid0_0_,pays0_.code_isoascode2_0_0_,pays0_.nomasnom0_0_,
06. pays0_.FK_DEVISEasFK4_0_0_frompayspays0_wherepays0_.FK_DEVISE=?
07. pays:id=3codeIso=Inom=Italie
08. pays:id=1codeIso=FRnom=France
09. pays:id=2codeIso=Dnom=Allemagne
10. pays:id=4codeIso=LUnom=Luxembourg
11. Devise:id=1code=EURlibelle=Euro
12. pays:id=3codeIso=Inom=Italie
13. pays:id=2codeIso=Dnom=Allemagne
14. pays:id=4codeIso=LUnom=Luxembourg
15. pays:id=1codeIso=FRnom=France
16. Devise:id=1code=EURlibelle=Euro
17. pays:id=4codeIso=LUnom=Luxembourg
18. pays:id=1codeIso=FRnom=France

19. pays:id=2codeIso=Dnom=Allemagne
https://www.jmdoudoux.fr/java/dej/chaphibernate.htm 91/105
24/04/2017 DvelopponsenJavaHibernate
19. pays:id=2codeIso=Dnom=Allemagne
20. pays:id=3codeIso=Inom=Italie

Les deux requtes ne sont plus effectues qu'une seule fois sur la base de donnes: pour les autres accs, les donnes de l'entit sont extraites du
cache des associations et du cache des entits.

Si le cache n'est pas activ sur l'entit possdant la relation many-to-one, alors l'entit est relue systmatiquement dans la base de donnes malgr
l'activation du cache sur la relation.

Rsultat :

01. Hibernate:selectdevise0_.IDasID1_0_,devise0_.CODEas
02. CODE1_0_,devise0_.LIBELLEasLIBELLE1_0_fromDEVISEdevise0_where
03. devise0_.ID=?
04. Devise:id=1code=EURlibelle=Euro
05. Hibernate:selectpays0_.FK_DEVISEasFK4_1_1_,pays0_.idasid1_,
06. pays0_.idasid0_0_,pays0_.code_isoascode2_0_0_,pays0_.nomasnom0_0_,
07. pays0_.FK_DEVISEasFK4_0_0_frompayspays0_wherepays0_.FK_DEVISE=?
08. pays:id=4codeIso=LUnom=Luxembourg
09. pays:id=2codeIso=Dnom=Allemagne
10. pays:id=3codeIso=Inom=Italie
11. pays:id=1codeIso=FRnom=France
12. Devise:id=1code=EURlibelle=Euro
13. Hibernate:selectpays0_.idasid0_0_,pays0_.code_isoas
14. code2_0_0_,pays0_.nomasnom0_0_,pays0_.FK_DEVISEasFK4_0_0_frompays
15. pays0_wherepays0_.id=?
16. Hibernate:selectpays0_.idasid0_0_,pays0_.code_isoas
17. code2_0_0_,pays0_.nomasnom0_0_,pays0_.FK_DEVISEasFK4_0_0_frompays
18. pays0_wherepays0_.id=?
19. Hibernate:selectpays0_.idasid0_0_,pays0_.code_isoas
20. code2_0_0_,pays0_.nomasnom0_0_,pays0_.FK_DEVISEasFK4_0_0_frompays
21. pays0_wherepays0_.id=?
22. Hibernate:selectpays0_.idasid0_0_,pays0_.code_isoas
23. code2_0_0_,pays0_.nomasnom0_0_,pays0_.FK_DEVISEasFK4_0_0_frompays
24. pays0_wherepays0_.id=?
25. pays:id=3codeIso=Inom=Italie
26. pays:id=4codeIso=LUnom=Luxembourg
27. pays:id=2codeIso=Dnom=Allemagne
28. pays:id=1codeIso=FRnom=France
29. Devise:id=1code=EURlibelle=Euro
30. Hibernate:selectpays0_.idasid0_0_,pays0_.code_isoas
31. code2_0_0_,pays0_.nomasnom0_0_,pays0_.FK_DEVISEasFK4_0_0_frompays
32. pays0_wherepays0_.id=?
33. Hibernate:selectpays0_.idasid0_0_,pays0_.code_isoas
34. code2_0_0_,pays0_.nomasnom0_0_,pays0_.FK_DEVISEasFK4_0_0_frompays
35. pays0_wherepays0_.id=?
36. Hibernate:selectpays0_.idasid0_0_,pays0_.code_isoas
37. code2_0_0_,pays0_.nomasnom0_0_,pays0_.FK_DEVISEasFK4_0_0_frompays
38. pays0_wherepays0_.id=?
39. Hibernate:selectpays0_.idasid0_0_,pays0_.code_isoas
40. code2_0_0_,pays0_.nomasnom0_0_,pays0_.FK_DEVISEasFK4_0_0_frompays
41. pays0_wherepays0_.id=?
42. pays:id=4codeIso=LUnom=Luxembourg
43. pays:id=1codeIso=FRnom=France
44. pays:id=3codeIso=Inom=Italie
45. pays:id=2codeIso=Dnom=Allemagne

Dans ce cas, l'utilisation du cache perd toute son efficacit. La requte pour obtenir les identifiants de la relation n'est bien effectue qu'une seule
fois et les donnes des invocations suivantes sont obtenues du cache. Cependant, comme l'entit pays n'est pas en cache, Hibernate qui ne possdent
que l'identifiant est oblig de refaire une lecture dans la base de donnes pour chaque entit.

C'est le mme comportement si le cache sur l'entit pays est activ mais le cache sur l'entit devise ne l'est pas.

Rsultat :

01. Hibernate:selectdevise0_.IDasID1_0_,devise0_.CODEas
02. CODE1_0_,devise0_.LIBELLEasLIBELLE1_0_fromDEVISEdevise0_where
03. devise0_.ID=?
04. Devise:id=1code=EURlibelle=Euro
05. Hibernate:selectpays0_.FK_DEVISEasFK4_1_1_,pays0_.idasid1_,
06. pays0_.idasid0_0_,pays0_.code_isoascode2_0_0_,pays0_.nomasnom0_0_,
07. pays0_.FK_DEVISEasFK4_0_0_frompayspays0_wherepays0_.FK_DEVISE=?
08. pays:id=4codeIso=LUnom=Luxembourg
09. pays:id=1codeIso=FRnom=France
10. pays:id=2codeIso=Dnom=Allemagne
11. pays:id=3codeIso=Inom=Italie
12. Hibernate:selectdevise0_.IDasID1_0_,devise0_.CODEas
13. CODE1_0_,devise0_.LIBELLEasLIBELLE1_0_fromDEVISEdevise0_where
14. devise0_.ID=?
15. Devise:id=1code=EURlibelle=Euro
16. pays:id=3codeIso=Inom=Italie
17. pays:id=1codeIso=FRnom=France
18. pays:id=4codeIso=LUnom=Luxembourg
19. pays:id=2codeIso=Dnom=Allemagne
20. Hibernate:selectdevise0_.IDasID1_0_,devise0_.CODEas
21. CODE1_0_,devise0_.LIBELLEasLIBELLE1_0_fromDEVISEdevise0_where
22. devise0_.ID=?
23. Devise:id=1code=EURlibelle=Euro
https://www.jmdoudoux.fr/java/dej/chaphibernate.htm 92/105
24/04/2017 DvelopponsenJavaHibernate
23. Devise:id=1code=EURlibelle=Euro
24. pays:id=3codeIso=Inom=Italie
25. pays:id=2codeIso=Dnom=Allemagne
26. pays:id=4codeIso=LUnom=Luxembourg
27. pays:id=1codeIso=FRnom=France

A chaque itration la devise est relue. La requte de la relation n'est effectue qu'une seule fois puisque les identifiants de son rsultat sont mis en
cache ainsi que les entits pays correspondantes.

La pire en termes de nombre de requtes effectues sur la base survient si le cache est activ sur la relation mais ne l'est pas pour les deux entits.

Rsultat :

01. Hibernate:selectdevise0_.IDasID1_0_,devise0_.CODEas
02. CODE1_0_,devise0_.LIBELLEasLIBELLE1_0_fromDEVISEdevise0_where
03. devise0_.ID=?
04. Devise:id=1code=EURlibelle=Euro
05. Hibernate:selectpays0_.FK_DEVISEasFK4_1_1_,pays0_.idasid1_,
06. pays0_.idasid0_0_,pays0_.code_isoascode2_0_0_,pays0_.nomasnom0_0_,
07. pays0_.FK_DEVISEasFK4_0_0_frompayspays0_wherepays0_.FK_DEVISE=?
08. pays:id=2codeIso=Dnom=Allemagne
09. pays:id=3codeIso=Inom=Italie
10. pays:id=1codeIso=FRnom=France
11. pays:id=4codeIso=LUnom=Luxembourg
12. Hibernate:selectdevise0_.IDasID1_0_,devise0_.CODEas
13. CODE1_0_,devise0_.LIBELLEasLIBELLE1_0_fromDEVISEdevise0_where
14. devise0_.ID=?
15. Devise:id=1code=EURlibelle=Euro
16. Hibernate:selectpays0_.idasid0_0_,pays0_.code_isoas
17. code2_0_0_,pays0_.nomasnom0_0_,pays0_.FK_DEVISEasFK4_0_0_frompays
18. pays0_wherepays0_.id=?
19. Hibernate:selectpays0_.idasid0_0_,pays0_.code_isoas
20. code2_0_0_,pays0_.nomasnom0_0_,pays0_.FK_DEVISEasFK4_0_0_frompays
21. pays0_wherepays0_.id=?
22. Hibernate:selectpays0_.idasid0_0_,pays0_.code_isoas
23. code2_0_0_,pays0_.nomasnom0_0_,pays0_.FK_DEVISEasFK4_0_0_frompays
24. pays0_wherepays0_.id=?
25. Hibernate:selectpays0_.idasid0_0_,pays0_.code_isoas
26. code2_0_0_,pays0_.nomasnom0_0_,pays0_.FK_DEVISEasFK4_0_0_frompayspays0_
27. wherepays0_.id=?
28. pays:id=4codeIso=LUnom=Luxembourg
29. pays:id=1codeIso=FRnom=France
30. pays:id=3codeIso=Inom=Italie
31. pays:id=2codeIso=Dnom=Allemagne
32. Hibernate:selectdevise0_.IDasID1_0_,devise0_.CODEas
33. CODE1_0_,devise0_.LIBELLEasLIBELLE1_0_fromDEVISEdevise0_where
34. devise0_.ID=?
35. Devise:id=1code=EURlibelle=Euro
36. Hibernate:selectpays0_.idasid0_0_,pays0_.code_isoas
37. code2_0_0_,pays0_.nomasnom0_0_,pays0_.FK_DEVISEasFK4_0_0_frompays
38. pays0_wherepays0_.id=?
39. Hibernate:selectpays0_.idasid0_0_,pays0_.code_isoas
40. code2_0_0_,pays0_.nomasnom0_0_,pays0_.FK_DEVISEasFK4_0_0_frompays
41. pays0_wherepays0_.id=?
42. Hibernate:selectpays0_.idasid0_0_,pays0_.code_isoas
43. code2_0_0_,pays0_.nomasnom0_0_,pays0_.FK_DEVISEasFK4_0_0_frompays
44. pays0_wherepays0_.id=?
45. Hibernate:selectpays0_.idasid0_0_,pays0_.code_isoas
46. code2_0_0_,pays0_.nomasnom0_0_,pays0_.FK_DEVISEasFK4_0_0_frompays
47. pays0_wherepays0_.id=?
48. pays:id=3codeIso=Inom=Italie
49. pays:id=1codeIso=FRnom=France
50. pays:id=4codeIso=LUnom=Luxembourg
51. pays:id=2codeIso=Dnom=Allemagne

Dans ce cas, la requte de la relation n'est effectue qu'une seule fois et les identifiants sont mis dans le cache. Pour les itrations suivantes,
Hibernate est oblig de relire les entits devises et pays puisque les identifiants correspondants ne sont pas trouvs dans le cache des entits.

54.12.7. Le cache des requtes

La mise en cache des rsultats d'une requte n'apporte pas toujours un gain significatif. Ce sont essentiellement les requtes qui sont frquemment
excutes avec les mmes paramtres qu'il est intressant de mettre en cache.

Par dfaut, l'activation du cache de second niveau ne met aucune requte dans le cache. Comme la plupart des requtes ne tireront pas de bnfice
tre mises en cache, aucune ne l'est par dfaut. Il faut explicitement demander la mise en cache d'une requte.

Hibernate utilise une combinaison de la requte SQL excute et des valeurs des paramtres de cette requte pour composer la valeur de la cl dans le
cache. La valeur associe cette cl est la liste des identifiants des entits retournes par la requte. Ainsi, si la requte est de nouveau invoque avec
les mmes paramtres, alors les identifiants des entits en rsultat seront directement retrouvs dans le cache.

Pour renvoyer le rsultat du cache des requtes, Hibernate va rechercher les entits dans le cache des entits partir des identifiants stocks dans le
cache des requtes. Si l'entit est trouve, alors une nouvelle instance est cre partir des informations du cache (cache de premier niveau ou cache
https://www.jmdoudoux.fr/java/dej/chaphibernate.htm 93/105
24/04/2017 DvelopponsenJavaHibernate
des entits) sinon l'entit est relue dans la base de donnes.

L'exemple de cette section va afficher la liste de tous les pays de la base de donnes, trois fois de suite. Cette opration va utiliser l'API Criteria qui
gnre une requte HQL, elle-mme transforme en requte SQL excute sur la base de donnes.

Exemple :

01. packagecom.jmdoudoux.test.hibernatecache;
02.
03. importjava.util.List;
04. importjava.util.Set;
05. importorg.hibernate.Session;
06. importorg.hibernate.SessionFactory;
07. importorg.hibernate.Transaction;
08. importorg.hibernate.cfg.Configuration;
09. importcom.jmdoudoux.test.hibernatecache.entity.Devise;
10. importcom.jmdoudoux.test.hibernatecache.entity.Pays;
11.
12. publicclassTestHibernateCache{
13. privatestaticSessionFactorysessionFactory=null;
14.
15. publicstaticvoidmain(String[]args){
16. try{
17. sessionFactory=newConfiguration().configure().buildSessionFactory();
18. for(inti=0;i<3;i++){
19. listerTousPays();
20. }
21. }catch(Throwableex){
22. System.err.println("Erreurdurantlestraitements"+ex);
23. }finally{
24. sessionFactory.close();
25. }
26. }
27.
28. publicstaticvoidlisterTousPays()throwsException{
29. Sessionsession=sessionFactory.openSession();
30. Transactiontx=null;
31. try{
32. tx=session.beginTransaction();
33. List<Pays>listPays=session.createCriteria(Pays.class).list();
34. for(Payspays:listPays){
35. System.out.println("pays:id="+pays.getId()+"codeIso="
36. +pays.getCodeIso()+"nom="+pays.getNom());
37. }
38. tx.commit();
39. }catch(Exceptione){
40. if(tx!=null){
41. tx.rollback();
42. }
43. throwe;
44. }finally{
45. session.close();
46. }
47. }
48. }

Rsultat :

01. Hibernate:selectthis_.idasid0_0_,this_.code_isoas
02. code2_0_0_,this_.nomasnom0_0_,this_.FK_DEVISEasFK4_0_0_frompaysthis_
03. pays:id=1codeIso=FRnom=France
04. pays:id=2codeIso=Dnom=Allemagne
05. pays:id=3codeIso=Inom=Italie
06. pays:id=4codeIso=LUnom=Luxembourg
07. pays:id=5codeIso=GBnom=GrandeBretagne
08. pays:id=6codeIso=USnom=EtatsUnis
09. pays:id=7codeIso=JAnom=Japon
10. Hibernate:selectthis_.idasid0_0_,this_.code_isoas
11. code2_0_0_,this_.nomasnom0_0_,this_.FK_DEVISEasFK4_0_0_frompaysthis_
12. pays:id=1codeIso=FRnom=France
13. pays:id=2codeIso=Dnom=Allemagne
14. pays:id=3codeIso=Inom=Italie
15. pays:id=4codeIso=LUnom=Luxembourg
16. pays:id=5codeIso=GBnom=GrandeBretagne
17. pays:id=6codeIso=USnom=EtatsUnis
18. pays:id=7codeIso=JAnom=Japon
19. Hibernate:selectthis_.idasid0_0_,this_.code_isoascode2_0_0_,
20. this_.nomasnom0_0_,this_.FK_DEVISEasFK4_0_0_frompaysthis_
21. pays:id=1codeIso=FRnom=France
22. pays:id=2codeIso=Dnom=Allemagne
23. pays:id=3codeIso=Inom=Italie
24. pays:id=4codeIso=LUnom=Luxembourg
25. pays:id=5codeIso=GBnom=GrandeBretagne
26. pays:id=6codeIso=USnom=EtatsUnis
27. pays:id=7codeIso=JAnom=Japon\n

A chaque itration, la requte est effectue sur la base de donnes pour obtenir les pays. Pour limiter le nombre de requtes effectues, il est possible
d'utiliser le cache des requtes.

https://www.jmdoudoux.fr/java/dej/chaphibernate.htm 94/105
24/04/2017 DvelopponsenJavaHibernate
Pour utiliser le cache des requtes, il faut:

activer et configurer le cache de second niveau (l'implmentation du cache utilis doit proposer un support du cache des requtes d'Hibernate)
activer l'utilisation du cache des requtes en passant la valeur true la proprit hibernate.cache.use_query_cache dans le fichier de
configuration d'Hibernate
activer le cache sur les entits qui seront renvoyes par les requtes mises en cache

Exemple :

01. <?xmlversion='1.0'encoding='utf8'?>
02. <!DOCTYPEhibernateconfigurationSYSTEM
03. "http://hibernate.org/dtd/hibernateconfiguration3.0.dtd">
04. <hibernateconfiguration>
05. <sessionfactory>
06. <!...>
07. <!Cachedesecondniveauactivavecehcache>
08. <propertyname="hibernate.cache.region.factory_class">
09. org.hibernate.cache.ehcache.SingletonEhCacheRegionFactory</property>
10. <!Activationducachedesrequtes>
11. <propertyname="hibernate.cache.use_query_cache">true</property>
12. <!...>
13. </sessionfactory>
14. </hibernateconfiguration>

Pour chaque requte que l'on souhaite mettre en cache, il faut invoquer la mthode setCacheable() en lui passant la valeur true en paramtre. La mise en
cache des requtes peut tre utilise sur des objets de type Criteria et Query.

Exemple :

01. publicstaticvoidlisterTousPays()throwsException{
02. Sessionsession=sessionFactory.openSession();
03. Transactiontx=null;
04. try{
05. tx=session.beginTransaction();
06. List<Pays>listPays=session.createCriteria(Pays.class)
07. .setCacheable(true).list();
08. for(Payspays:listPays){
09. System.out.println("pays:id="+pays.getId()+"codeIso="
10. +pays.getCodeIso()+"nom="+pays.getNom());
11. }
12. tx.commit();
13. }catch(Exceptione){
14. if(tx!=null){
15. tx.rollback();
16. }
17. throwe;
18. }finally{
19. session.close();
20. }
21. }

Rsultat :

01. Hibernate:selectpays0_.idasid0_,pays0_.code_isoascode2_0_,
02. pays0_.nomasnom0_,pays0_.FK_DEVISEasFK4_0_frompayspays0_
03. pays:id=1codeIso=FRnom=France
04. pays:id=2codeIso=Dnom=Allemagne
05. pays:id=3codeIso=Inom=Italie
06. pays:id=4codeIso=LUnom=Luxembourg
07. pays:id=5codeIso=GBnom=GrandeBretagne
08. pays:id=6codeIso=USnom=EtatsUnis
09. pays:id=7codeIso=JAnom=Japon
10. pays:id=1codeIso=FRnom=France
11. pays:id=2codeIso=Dnom=Allemagne
12. pays:id=3codeIso=Inom=Italie
13. pays:id=4codeIso=LUnom=Luxembourg
14. pays:id=5codeIso=GBnom=GrandeBretagne
15. pays:id=6codeIso=USnom=EtatsUnis
16. pays:id=7codeIso=JAnom=Japon
17. pays:id=1codeIso=FRnom=France
18. pays:id=2codeIso=Dnom=Allemagne
19. pays:id=3codeIso=Inom=Italie
20. pays:id=4codeIso=LUnom=Luxembourg
21. pays:id=5codeIso=GBnom=GrandeBretagne
22. pays:id=6codeIso=USnom=EtatsUnis
23. pays:id=7codeIso=JAnom=Japon\n

La requte n'est excute qu'une seule fois car pour les itrations suivantes les donnes sont extraites du cache des requtes et du cache des entits.

Le mode de fonctionnement est identique pour des requtes HQL.

Exemple :

https://www.jmdoudoux.fr/java/dej/chaphibernate.htm 95/105
24/04/2017 DvelopponsenJavaHibernate
01. publicstaticvoidlisterTousPays()throwsException{
02. Sessionsession=sessionFactory.openSession();
03. Transactiontx=null;
04. try{
05. tx=session.beginTransaction();
06. Queryquery=session.createQuery("fromPays").setCacheable(true);
07. List<Pays>listPays=query.list();
08. for(Payspays:listPays){
09. System.out.println("pays:id="+pays.getId()+"codeIso="
10. +pays.getCodeIso()+"nom="+pays.getNom());
11. }
12. tx.commit();
13. }catch(Exceptione){
14. if(tx!=null){
15. tx.rollback();
16. }
17. throwe;
18. }finally{
19. session.close();
20. }
21. }

Le rsultat l'excution est le mme mais le temps est rduit.

Le cache des requtes ne stocke pas les entits qui sont retournes par la requtes mais uniquement la valeur de leur identifiant et leur type. Pour tirer
pleinement parti du cache des requtes, il est donc important de le coupler avec l'utilisation du cache de second niveau des entits.

Il est important que le cache soit activ sur les entits en rsultat des requtes qui sont mises dans le cache des requtes. La cl du cache est la
requte et la valeur ne contient que les identifiants des entits. Celles-ci doivent tre lues soit dans le cache des entits soit tre relues de la base de
donnes.

Dans l'exemple ci-dessous, l'entit Pays n'est pas mise en cache.

Rsultat :

01. \n
02. Hibernate:
03. selectpays0_.idasid0_,pays0_.code_isoascode2_0_,pays0_.nomasnom0_,
04. pays0_.FK_DEVISEasFK4_0_frompayspays0_
05. pays:id=1codeIso=FRnom=France
06. pays:id=2codeIso=Dnom=Allemagne
07. pays:id=3codeIso=Inom=Italie
08. pays:id=4codeIso=LUnom=Luxembourg
09. pays:id=5codeIso=GBnom=GrandeBretagne
10. pays:id=6codeIso=USnom=EtatsUnis
11. pays:id=7codeIso=JAnom=Japon
12. Hibernate:selectpays0_.idasid0_0_,pays0_.code_isoas
13. code2_0_0_,pays0_.nomasnom0_0_,pays0_.FK_DEVISEasFK4_0_0_frompays
14. pays0_wherepays0_.id=?
15. Hibernate:selectpays0_.idasid0_0_,pays0_.code_isoas
16. code2_0_0_,pays0_.nomasnom0_0_,pays0_.FK_DEVISEasFK4_0_0_frompays
17. pays0_wherepays0_.id=?
18. Hibernate:selectpays0_.idasid0_0_,pays0_.code_isoas
19. code2_0_0_,pays0_.nomasnom0_0_,pays0_.FK_DEVISEasFK4_0_0_frompays
20. pays0_wherepays0_.id=?
21. Hibernate:selectpays0_.idasid0_0_,pays0_.code_isoas
22. code2_0_0_,pays0_.nomasnom0_0_,pays0_.FK_DEVISEasFK4_0_0_frompays
23. pays0_wherepays0_.id=?
24. Hibernate:selectpays0_.idasid0_0_,pays0_.code_isoas
25. code2_0_0_,pays0_.nomasnom0_0_,pays0_.FK_DEVISEasFK4_0_0_frompays
26. pays0_wherepays0_.id=?
27. Hibernate:selectpays0_.idasid0_0_,pays0_.code_isoas
28. code2_0_0_,pays0_.nomasnom0_0_,pays0_.FK_DEVISEasFK4_0_0_frompays
29. pays0_wherepays0_.id=?
30. Hibernate:selectpays0_.idasid0_0_,pays0_.code_isoas
31. code2_0_0_,pays0_.nomasnom0_0_,pays0_.FK_DEVISEasFK4_0_0_frompays
32. pays0_wherepays0_.id=?
33. pays:id=1codeIso=FRnom=France
34. pays:id=2codeIso=Dnom=Allemagne
35. pays:id=3codeIso=Inom=Italie
36. pays:id=4codeIso=LUnom=Luxembourg
37. pays:id=5codeIso=GBnom=GrandeBretagne
38. pays:id=6codeIso=USnom=EtatsUnis
39. pays:id=7codeIso=JAnom=Japon
40. Hibernate:selectpays0_.idasid0_0_,pays0_.code_isoas
41. code2_0_0_,pays0_.nomasnom0_0_,pays0_.FK_DEVISEasFK4_0_0_frompays
42. pays0_wherepays0_.id=?
43. Hibernate:selectpays0_.idasid0_0_,pays0_.code_isoas
44. code2_0_0_,pays0_.nomasnom0_0_,pays0_.FK_DEVISEasFK4_0_0_frompays
45. pays0_wherepays0_.id=?
46. Hibernate:selectpays0_.idasid0_0_,pays0_.code_isoas
47. code2_0_0_,pays0_.nomasnom0_0_,pays0_.FK_DEVISEasFK4_0_0_frompays
48. pays0_wherepays0_.id=?
49. Hibernate:selectpays0_.idasid0_0_,pays0_.code_isoas
50. code2_0_0_,pays0_.nomasnom0_0_,pays0_.FK_DEVISEasFK4_0_0_frompays
51. pays0_wherepays0_.id=?
52. Hibernate:selectpays0_.idasid0_0_,pays0_.code_isoas
53. code2_0_0_,pays0_.nomasnom0_0_,pays0_.FK_DEVISEasFK4_0_0_frompays
54. pays0_wherepays0_.id=?
55. Hibernate:selectpays0_.idasid0_0_,pays0_.code_isoas
56. code2_0_0_,pays0_.nomasnom0_0_,pays0_.FK_DEVISEasFK4_0_0_frompays

57. pays0_wherepays0_.id=?
https://www.jmdoudoux.fr/java/dej/chaphibernate.htm 96/105
24/04/2017 DvelopponsenJavaHibernate
57. pays0_wherepays0_.id=?
58. Hibernate:selectpays0_.idasid0_0_,pays0_.code_isoas
59. code2_0_0_,pays0_.nomasnom0_0_,pays0_.FK_DEVISEasFK4_0_0_frompays
60. pays0_wherepays0_.id=?
61. pays:id=1codeIso=FRnom=France
62. pays:id=2codeIso=Dnom=Allemagne
63. pays:id=3codeIso=Inom=Italie
64. pays:id=4codeIso=LUnom=Luxembourg
65. pays:id=5codeIso=GBnom=GrandeBretagne
66. pays:id=6codeIso=USnom=EtatsUnis
67. pays:id=7codeIso=JAnom=Japon\n

La requte pour obtenir tous les pays est bien excute une seule fois et mise en cache. Malheureusement comme l'entit pays n'est pas mise en cache,
Hibernate n'a pas d'autre solution que de relire chaque entit dans la base de donnes, ce qui a un effet catastrophique sur les performances car au lieu
d'une seule requte sur la base de donnes, ce sont de nombreuses requtes qui sont excutes.

Pour viter Hibernate de faire des relectures pour chacune des entits, il est prfrable d'activer la mise en cache des entits concernes. Il est
donc important d'utiliser en conjonction le cache des requtes et le cache des entits: le type des entits retournes par les rsultats d'une requte
mise en cache doit tre configur pour tre pris en compte par le cache des entits.

Le cache des requtes d'Hibernate utilise deux rgions particulires par dfaut:

org.hibernate.cache.StandardQueryCache: stocke les identifiants des entits retournes par une requte pour des paramtres donns
org.hibernate.cache.UpdateTimestampsCache : stocke pour chaque table la date/heure de dernire mise jour d'un enregistrement. Chaque
modification dans une table met jour la date de dernire modification dans l'entre correspondante de cette rgion du cache.

Il est trs important que la rgion UpdateTimestampsCache soit configure pour ne jamais tre invalide priodiquement.

Il est possible de configurer une rgion ddie du cache pour stocker le rsultat de certaines requtes. Cette configuration particulire peut
notamment permettre de dfinir la stratgie d'viction du contenu du cache. Par dfaut, les requtes mises en cache le sont dans la rgion par dfaut
pour les requtes. Pour prciser une autre rgion, il faut prciser son nom en invoquant la mthode setCacheRegion().

Exemple :

1. Queryquery=session.createQuery("fromPays").setCacheable(true)
2. .setCacheRegion("query.pays");
3. List<Pays>listPays=query.list();

Si plusieurs rgions peuvent tre utilises pour mettre en cache les requtes, il ne peut y avoir qu'une seule rgion de type timestamps.

La rgion UpdateTimestampsCache permet Hibernate de stocker la date/heure de dernire mise jour pour toutes les tables utilises.

Hibernate utilise les donnes de la rgion UpdateTimestampCache pour invalider les donnes contenues dans la rgion StandardQueryCache : Hibernate
invalide le contenu du cache pour une requte si, pour une des tables figurant dans le rsultat, la date/heure de mise en cache de la requte est
antrieure celle de la dernire modification stocke dans la rgion UpdateTimestampsCache.

En d'autres termes, lorsqu'une requte qui a t mise en cache est rexcute, Hibernate vrifie la date/heure de dernire modification (insert,
update ou delete) dans la ou les tables utilises comme rsultat. Si cette date/heure est plus rcente que la date/heure de mise en cache des rsultats
de la requte alors celle-ci est invalide dans le cache et la requte est rexcute sur la base de donnes.

La date/heure stocke dans la rgion UpdateTimestampsCache concerne une mise jour sur n'importe quelle occurrence de la table.

La mthode setCacheMode() des interfaces Query et Criteria permet de modifier le mode d'utilisation du cache pour la requte selon l'instance de
type CacheMode fournie en paramtre.

Instance Rle

CacheMode.NORMAL Des lments peuvent tre lus et crits dans le cache

CacheMode.GET Les lments peuvent tre uniquement lus du cache

CacheMode.PUT Les lments ne sont pas lus du cache mais ils sont crits dans le cache lorsqu'ils sont lus dans la base de donnes

CacheMode.IGNORE Les lments ne sont ni lus ni crits dans le cache

CacheMode.REFRESH Forcer le rafraichissement des lments du cache

En passant la valeur CacheMode.REFRESH la mthode setCacheMode(), Hibernate ne va pas rechercher le rsultat de la requte dans le cache mais
excuter la requte et insrer ou remplacer le rsultat dans le cache. Ceci permet de forcer le rafrachissement des donnes du cache : c'est
particulirement utile si un autre processus met jour la base de donnes pour des donnes rfrences dans le cache.

Il est ncessaire d'tre prudent lors de l'utilisation du cache des requtes.

Le cache des requtes doit tre utilis avec soin car son activation peut introduire une certaine latence et limiter les possibilits de monte en charge.

Il est par exemple contre-productif :

d'activer le cache des requtes si celui-ci n'est pas utilis.


de mettre en cache les rsultats d'une requte dont la ou les tables des entits concernes sont modifies frquemment impliquant de fait une
invalidation des rsultats dans le cache

https://www.jmdoudoux.fr/java/dej/chaphibernate.htm 97/105
24/04/2017 DvelopponsenJavaHibernate
Une modification dans une table implique la mise jour du cache timestamps pour la table et invalide automatiquement les rsultats d'une requte du
cache qui contiennent au moins une entit de cette table mme si la modification ne concerne pas cette entit. Si une table est souvent modifie, le
taux de hit dans le cache est trs bas puisque les donnes du cache sont frquemment invalides.

Le cache des requtes peut tre assez consommateur en ressources surtout si de nombreuses requtes avec leurs paramtres sont mises en cache. Les
requtes SQL sont gnralement composes de plusieurs centaines de caractres frquemment utilises avec des paramtres diffrents.

La mise jour du cache des timestamps introduit une contention lie la pose d'un verrou. Ce verrou est mis en oeuvre chaque accs au cache ce qui
peut crer un goulot d'tranglement lorsque la charge augmente ou lorsque la mme table est mise jour par plusieurs threads.

L'utilisation du cache des requtes induit donc un certain surcot dans les traitements transactionnels. Ceci est particulirement vrai si les entits
mises en cache sont mises jour car dans ce cas Hibernate doit invalider certaines donnes du cache.

54.12.8. La gestion du cache de second niveau

Jusqu' la version 3.3 d'Hibernate incluse, la classe SessionFactory proposait plusieurs mthodes pour retirer des donnes du cache de second niveau.

Mthode Rle

void evict(Class persistentClass) Retirer du cache toutes les donnes d'un type d'entit

void evict(Class persistentClass,


Retirer du cache les donnes d'une entit dont l'identifiant est fourni en paramtre
Serializable id)

void evictCollection(String roleName) Supprimer toutes les donnes d'une association dont le nom est fourni en paramtre

void evictCollection(String roleName, Supprimer les donnes d'une association dont le nom est fourni en paramtres etconcernant l'entit
Serializable id) dont l'identifiant est fourni

void evictEntity(String entityName) Supprimer toutes les donnes du type d'entit dont le nom est fourni en paramtre

void evictEntity(String entityName,


Supprimer les donnes d'une entit dont le type et l'identifiant sont fournis en paramtres
Serializable id)

void evictQueries() Supprimer tout le contenu de la rgion par dfaut du cache des requtes

Supprimer tout le contenu d'une rgion particulire du cache des requtes dont le nom est pass en
void evictQueries(String cacheRegion)
paramtre

La mthode getAllClassMetadata() renvoie une map dont la cl est le nom de l'entit et la valeur est un objet de type ClassMetadata qui encapsule les
mtadonnes de l'entit.

La mthode getAllCollectionMetadata() renvoie une map dont la cl est le nom de l'association et la valeur est un objet de type CollectionMetadata qui
encapsule les mtadonnes de l'association.

L'exemple ci-dessous purge entirement le contenu du cache de second niveau (associations, entits et requtes).

Exemple :

01. Map<String,CollectionMetadata>collectionMetadatas=
02. sessionFactory.getAllCollectionMetadata();
03. for(Stringnom:collectionMetadatas.keySet()){
04. sessionFactory.evictCollection(nom);
05. }
06.
07. Map<String,ClassMetadata>classMetadatas=sessionFactory.getAllClassMetadata();
08. for(Stringnom:classMetadatas.keySet()){
09. sessionFactory.evictEntity(nom);
10. }
11.
12. sessionFactory.evictQueries();

A partir de la version 3.5 d'Hibernate, toutes les mthodes de l'interface SessionFactory relatives la gestion du contenudu cache sont deprecated
(evit(), evictCollection(), evictEntity(), evictQueries()): il faut utiliser un objet de type Cache.

Un objet de type Cache est obtenu en invoquant la mthode getCache() de la SessionFactory. L'interface Cache dcrit les fonctionnalits permettant
de dterminer la prsence et de supprimer des donnes dans les rgions du cache de second niveau.

Mthode Rle

boolean containsCollection(String role, Serializable


Renvoyer un boolen qui permet de prciser si une association est prsente dans le cache
ownerIdentifier)

boolean containsEntity(Class entityClass, Serializable


Renvoyer un boolen qui permet de prciser si une entit est prsente dans le cache
identifier)

boolean containsEntity(String entityName, Serializable


Renvoyer un boolen qui permet de prciser si une entit est prsente dans le cache
identifier)

https://www.jmdoudoux.fr/java/dej/chaphibernate.htm 98/105
24/04/2017 DvelopponsenJavaHibernate
boolean containsQuery(String regionName) Renvoyer un boolen qui permet de prciser si une rgion utilise pour le cache des requtes
contient des lments

void evictCollection(String role, Serializable


Supprimer des lments du cache de second niveau relatifs une association
ownerIdentifier)

void evictCollectionRegion(String role) Supprimer les donnes des entits du cache de second niveau relatives une association

void evictCollectionRegions() Supprimer tous les lments des rgions du cache relatives aux associations

void evictDefaultQueryRegion() Supprimer les lments de la rgion par dfaut du cache des requtes

void evictEntity(Class entityClass, Serializable


Supprimer les donnes d'une entit du cache de second niveau
identifier)

void evictEntity(String entityName, Serializable


Supprimer les donnes d'une entit du cache de second niveau
identifier)

void evictEntityRegion(Class entityClass) Supprimer toutes les donnes d'une entit

void evictEntityRegion(String entityName) Supprimer toutes les donnes d'une entit

void evictEntityRegions() Supprimer toutes les donnes des caches des entits

void evictQueryRegion(String regionName) Supprimer toutes les donnes de la rgion du cache des requtes

void evictQueryRegions() Supprimer toutes les donnes de toutes les rgions utilises pour le cache des requtes

Attention: aucune de ces mthodes ne prend en compte un aspect transactionnel: leur excution est immdiate sans gestion des accs concurrents
raliss par les transactions en cours.

Exemple :

1. Cachecache=sessionFactory.getCache();
2.
3. System.out.println(cache.containsEntity(Pays.class,2));
4.
5. Cache.evictEntity(Pays.class,2);

54.12.9. Le monitoring de l'utilisation du cache

Une fois un cache de second niveau mis en place, il est ncessaire de rgulirement surveiller son activit pour vrifier sa bonne utilisation et
ventuellement modifier sa configuration pour obtenir les meilleures performances.

L'utilisation du cache de second niveau implique que l'accs aux donnes de ce cache peut russir (hit) ou chouer (miss).

Il est possible de demander Hibernate d'tre verbeux sur l'utilisation du cache dans les logs en utilisant le niveau DEBUG pour le logger
org.hibernate.cache.

Exemple :

1. <loggername="org.hibernate.cache">
2. <levelvalue="DEBUG"/>
3. </logger>

L'inconvnient de cette activation est qu'elle est trs verbeuse.

Hibernate propose un mcanisme de calcul de statistiques sur son activit incluant entre autres des informations sur l'utilisation du cache. Ce
mcanisme doit tre activ en donnant la valeur true la proprit hibernate.generate_statistics.

L'inconvnient des statistiques est qu'elles consomment de la ressource mais aussi qu'elles induisent une lgre dgradation des performances lie la
gestion des accs concurrents.

Hibernate propose des statistiques sur l'utilisation de l'objet de type SessionFactory. Une API permet de les consulter et elles sont facilement
exposables sous la forme d'un MBean JMX.

54.12.9.1. L'activation et l'obtention de donnes statistiques

Les statistiques permettent d'obtenir des informations utiles sur l'utilisation du cache et des sessions:

Obtenir des informations globales: le nombre d'entits obtenues du cache (hit), le nombre d'entits non obtenues du cache (miss), ...

https://www.jmdoudoux.fr/java/dej/chaphibernate.htm 99/105
24/04/2017 DvelopponsenJavaHibernate
Obtenir des informations prcises sur l'utilisation dans le cache d'une entit ou d'une association particulire (EntityStatistics et
CollectionStatistics)
Obtenir des informations sur l'excution des requtes mises en cache (QueryStatistics)
Obtenir des informations sur l'utilisation d'une rgion particulire du cache (SecondLevelCacheStatistics)

Hibernate propose des statistiques d'utilisation fournies par la classe SessionFactory. Ces informations sont disponibles de deux manires:

La publication par JMX en activant le MBean StatisticsService


L'utilisation de la mthode getStatistics() de la classe SessionFactory

Par dfaut, les statistiques sont dsactives. Il y a deux manires de les activer:

en utilisant la proprit hibernate.generate_statistics du fichier de configuration d'Hibernate et en lui passant la valeur true

Exemple :

1. <propkey="hibernate.generate_statistics">true</prop>\n

en invoquant la mthode SessionFactory.getStatistics().setStatisticsEnabled() et en lui passant la valeur true en paramtre

Exemple :

1. Statisticsstatistics=sessionFactory.getStatistics();
2. statistics.setStatisticsEnabled(true);

Plusieurs mthodes concernent les statistiques sur l'utilisation des sessions :

Mthode Rle

long getCloseStatementCount() Obtenir le nombre d'objets de type PrepareStatement qui ont t ferms

long getCollectionFetchCount()

long getCollectionLoadCount() Obtenir le nombre d'associations lues de la base de donnes

long getCollectionRecreateCount()

long getCollectionRemoveCount() Obtenir le nombre d'associations supprimes

String[] getCollectionRoleNames() Obtenir le nom de toutes les associations

long getCollectionUpdateCount() Obtenir le nombre d'associations mises jour

long getConnectCount() Obtenir le nombre de connexions demandes par les sessions

long getEntityDeleteCount() Obtenir le nombre d'entits supprimes dans la base de donnes

long getEntityFetchCount()

long getEntityInsertCount() Obtenir le nombre d'entits insres dans la base de donnes

long getEntityLoadCount() Obtenir le nombre d'entits lues de la base de donnes

String[] getEntityNames() Obtenir le nom de toutes les entits

long getEntityUpdateCount() Obtenir le nombre d'entits mises jour

long getFlushCount() Obtenir le nombre de flushes implicites ou explicites fait par les sessions

long getOptimisticFailureCount() Obtenir le nombre d'exceptions de type StaleObjectStateExceptions qui sont leves

long getPrepareStatementCount() Obtenir le nombre de PrepareStatement

String[] getQueries() Obtenir les requtes SQL excutes

long getQueryExecutionCount() Obtenir le nombre de requtes excutes

long getQueryExecutionMaxTime() Obtenir le temps de la requte dont l'excution est la plus longue

String getQueryExecutionMaxTimeQueryString() Obtenir la requte dont le temps d'excution est le plus long

long getSessionCloseCount() Obtenir le nombre de sessions fermes

long getSessionOpenCount() Obtenir le nombre de sessions ouvertes

long getSuccessfulTransactionCount() Obtenir le nombre de transactions qui ont russies

long getTransactionCount() Obtenir le nombre de transactions utilises

Plusieurs mthodes permettent d'obtenir le nom des rgions utilises par le cache de second niveau : getEntityNames(), getCollectionRoleNames(),
getQueries() et getSecondLevelCacheRegionNames().

Plusieurs mthodes concernent l'utilisation du cache de second niveau et des rgions qu'il utilise.

https://www.jmdoudoux.fr/java/dej/chaphibernate.htm 100/105
24/04/2017 DvelopponsenJavaHibernate
Mthode Rle

CollectionStatistics getCollectionStatistics(String role) Obtenir des statistiques pour une association

EntityStatistics getEntityStatistics(String entityName) Obtenir des statistiques pour une entit

long getQueryCacheHitCount() Obtenir le nombre de requtes obtenues du cache

long getQueryCacheMissCount() Obtenir le nombre de requtes non obtenues du cache

long getQueryCachePutCount() Obtenir le nombre de requtes mises en cache

QueryStatistics getQueryStatistics(String queryString) Obtenir des statistiques pour une requte

long getSecondLevelCacheHitCount() Obtenir le nombre d'entits et d'associations obtenues du cache

Obtenir le nombre d'entits et d'associations non obtenues du cache et donc relues


long getSecondLevelCacheMissCount()
de la base de donnes

long getSecondLevelCachePutCount() Obtenir le nombre d'entits et associations mises dans le cache

String[] getSecondLevelCacheRegionNames() Obtenir le nom de toutes les rgions du cache

SecondLevelCacheStatistics
Obtenir les statistiques d'utilisation d'une rgion
getSecondLevelCacheStatistics(String regionName)

Plusieurs mthodes concernent la gestion des statistiques

Mthode Rle

void clear() Rinitialiser toutes les valeurs de statistiques

long getStartTime() Date/heure de dmarrage (en ms) de calcul des statistiques

boolean isStatisticsEnabled() Renvoyer un boolen qui prcise si les statistiques sont calcules ou non

void logSummary() Inscrire dans le journal un rsum des statistiques

void setStatisticsEnabled(boolean b) Activer ou non le calcul des statistiques

La mthode clear() de la classe Statistics permet de rinitialiser les valeurs des statistiques calcules par Hibernate.

La mthode logSummary() de la classeStatistics permet d'envoyer dans le journal un rsum des statistiques calcules par Hibernate avec un niveau
Info.

Rsultat :

01. INFO[main]:org.hibernate.stat.internal.ConcurrentStatisticsImplHHH000161:
02. Loggingstatistics....
03. INFO[main]:org.hibernate.stat.internal.ConcurrentStatisticsImplHHH000251:
04. Starttime:1342448010929
05. INFO[main]:org.hibernate.stat.internal.ConcurrentStatisticsImplHHH000242:
06. Sessionsopened:3
07. INFO[main]:org.hibernate.stat.internal.ConcurrentStatisticsImplHHH000241:
08. Sessionsclosed:3
09. INFO[main]:org.hibernate.stat.internal.ConcurrentStatisticsImplHHH000266:
10. Transactions:3
11. INFO[main]:org.hibernate.stat.internal.ConcurrentStatisticsImplHHH000258:
12. Successfultransactions:3
13. INFO[main]:org.hibernate.stat.internal.ConcurrentStatisticsImplHHH000187:
14. Optimisticlockfailures:0
15. INFO[main]:org.hibernate.stat.internal.ConcurrentStatisticsImplHHH000105:
16. Flushes:3
17. INFO[main]:org.hibernate.stat.internal.ConcurrentStatisticsImplHHH000048:
18. Connectionsobtained:3
19. INFO[main]:org.hibernate.stat.internal.ConcurrentStatisticsImplHHH000253:
20. Statementsprepared:1
21. INFO[main]:org.hibernate.stat.internal.ConcurrentStatisticsImplHHH000252:
22. Statementsclosed:0
23. INFO[main]:org.hibernate.stat.internal.ConcurrentStatisticsImplHHH000239:
24. Secondlevelcacheputs:7
25. INFO[main]:org.hibernate.stat.internal.ConcurrentStatisticsImplHHH000237:
26. Secondlevelcachehits:14
27. INFO[main]:org.hibernate.stat.internal.ConcurrentStatisticsImplHHH000238:
28. Secondlevelcachemisses:0
29. INFO[main]:org.hibernate.stat.internal.ConcurrentStatisticsImplHHH000079:
30. Entitiesloaded:7
31. INFO[main]:org.hibernate.stat.internal.ConcurrentStatisticsImplHHH000080:
32. Entitiesupdated:0
33. INFO[main]:org.hibernate.stat.internal.ConcurrentStatisticsImplHHH000078:
34. Entitiesinserted:0
35. INFO[main]:org.hibernate.stat.internal.ConcurrentStatisticsImplHHH000076:
36. Entitiesdeleted:0
37. INFO[main]:org.hibernate.stat.internal.ConcurrentStatisticsImplHHH000077:
38. Entitiesfetched(minimizethis):0
39. INFO[main]:org.hibernate.stat.internal.ConcurrentStatisticsImplHHH000033:
40. Collectionsloaded:0
41. INFO[main]:org.hibernate.stat.internal.ConcurrentStatisticsImplHHH000036:
42. Collectionsupdated:0
43. INFO[main]:org.hibernate.stat.internal.ConcurrentStatisticsImplHHH000035:
44. Collectionsremoved:0
https://www.jmdoudoux.fr/java/dej/chaphibernate.htm 101/105
24/04/2017 DvelopponsenJavaHibernate
44. Collectionsremoved:0
45. INFO[main]:org.hibernate.stat.internal.ConcurrentStatisticsImplHHH000034:
46. Collectionsrecreated:0
47. INFO[main]:org.hibernate.stat.internal.ConcurrentStatisticsImplHHH000032:
48. Collectionsfetched(minimizethis):0
49. INFO[main]:org.hibernate.stat.internal.ConcurrentStatisticsImplHHH000438:
50. NaturalIdcacheputs:0
51. INFO[main]:org.hibernate.stat.internal.ConcurrentStatisticsImplHHH000439:
52. NaturalIdcachehits:0
53. INFO[main]:org.hibernate.stat.internal.ConcurrentStatisticsImplHHH000440:
54. NaturalIdcachemisses:0
55. INFO[main]:org.hibernate.stat.internal.ConcurrentStatisticsImplHHH000441:
56. MaxNaturalIdquerytime:0ms
57. INFO[main]:org.hibernate.stat.internal.ConcurrentStatisticsImplHHH000442:
58. NaturalIdqueriesexecutedtodatabase:0
59. INFO[main]:org.hibernate.stat.internal.ConcurrentStatisticsImplHHH000210:
60. Queriesexecutedtodatabase:1
61. INFO[main]:org.hibernate.stat.internal.ConcurrentStatisticsImplHHH000215:
62. Querycacheputs:1
63. INFO[main]:org.hibernate.stat.internal.ConcurrentStatisticsImplHHH000433:
64. updatetimestampscacheputs:0
65. INFO[main]:org.hibernate.stat.internal.ConcurrentStatisticsImplHHH000434:
66. updatetimestampscachehits:0
67. INFO[main]:org.hibernate.stat.internal.ConcurrentStatisticsImplHHH000435:
68. updatetimestampscachemisses:2
69. INFO[main]:org.hibernate.stat.internal.ConcurrentStatisticsImplHHH000213:
70. Querycachehits:2
71. INFO[main]:org.hibernate.stat.internal.ConcurrentStatisticsImplHHH000214:
72. Querycachemisses:1
73. INFO[main]:org.hibernate.stat.internal.ConcurrentStatisticsImplHHH000173:
74. Maxquerytime:455ms

Plusieurs classes permettent d'obtenir des informations sur une rgion particulire du cache.

Attention : les informations temporelles fournies par les statistiques possdent une prcision qui dpend de la JVM et est gnralement est de 3
millisecondes ou plus.

La classe EntityStatistics encapsule des informations statistiques sur une entit du cache. Elle possde plusieurs mthodes pour obtenir les valeurs:

Mthodes Rles

long getLoadCount() Nombre d'entits lues

long getFetchCount()

long getInsertCount() Nombre d'entits ajoutes

long getDeleteCount() Nombre d'entits supprimes

long getUpdateCount() Nombre d'entits mises jour

long getOptimisticFailureCount() Nombre de verrous optimistes qui ont chous

Exemple :

01. Statisticsstats=sessionFactory.getStatistics();
02. EntityStatisticsentityStats=stats
03. .getEntityStatistics("com.jmdoudoux.test.hibernatecache.entity.Pays");
04. System.out.println(entityStats.getFetchCount());
05. System.out.println(entityStats.getLoadCount());
06. System.out.println(entityStats.getInsertCount());
07. System.out.println(entityStats.getUpdateCount());
08. System.out.println(entityStats.getDeleteCount());
09. System.out.println(entityStats.getOptimisticFailureCount());

La classe CollectionStatistics encapsule des informations statistiques sur une collection du cache. Elle possde plusieurs mthodes pour obtenir les
valeurs:

Mthodes Rles

long getLoadCount()

long getFetchCount()

long getRecreateCount()

long getRemoveCount()

long getUpdateCount()

Exemple :

1. Statisticsstats=sessionFactory.getStatistics();
2. CollectionStatisticscollectionStats=stats
3. .getCollectionStatistics("com.jmdoudoux.test.hibernatecache.entity.Devise.pays");
4. System.out.println(collectionStats.getFetchCount());
https://www.jmdoudoux.fr/java/dej/chaphibernate.htm 102/105
24/04/2017 DvelopponsenJavaHibernate
4. System.out.println(collectionStats.getFetchCount());
5. System.out.println(collectionStats.getLoadCount());
6. System.out.println(collectionStats.getRecreateCount());
7. System.out.println(collectionStats.getRemoveCount());
8. System.out.println(collectionStats.getUpdateCount());

La classe QueryStatistics encapsule des informations statistiques sur une requte du cache. Elle possde plusieurs mthodes pour obtenir les valeurs:

Mthodes Rles

long getCacheHitCount() Nombre d'objets retrouvs dans le cache lors des excutions de cette requte

long getCacheMissCount() Nombre d'objets non retrouvs dans le cache lors des excutions de cette requte

long getCachePutCount() Nombre d'objets mis dans le cache suite aux excutions de cette requte

long getExecutionAvgTime() Temps moyen d'excution de la requte

long getExecutionCount() Nombre d'invocations de la requte

long getExecutionMaxTime() Temps maximum d'excution de la requte

long getExecutionMinTime() Temps minimum d'excution de la requte

long getExecutionRowCount() Nombre d'entits retournes par toutes les invocations de la requte

Exemple :

01. Statisticsstats=sessionFactory.getStatistics();
02. QueryStatisticsqueryStats=stats.getQueryStatistics("fromPays");
03. System.out.println(queryStats.getCacheHitCount());
04. System.out.println(queryStats.getCacheMissCount());
05. System.out.println(queryStats.getCachePutCount());
06. System.out.println(queryStats.getExecutionAvgTime());
07. System.out.println(queryStats.getExecutionCount());
08. System.out.println(queryStats.getExecutionMaxTime());
09. System.out.println(queryStats.getExecutionMinTime());
10. System.out.println(queryStats.getExecutionRowCount());

La classe SecondLevelCacheStatistics encapsule des informations statistiques sur l'utilisation d'une rgion du cache. Elle possde plusieurs mthodes
pour obtenir les valeurs:

Mthodes Rles

long getHitCount() Nombre d'lments obtenus de la rgion

long getMissCount() Nombre d'lments non obtenus de la rgion

long getPutCount() Nombre d'lments insrs dans la rgion

long getElementCountInMemory() Nombre d'lments dans la rgion en mmoire

long getElementCountOnDisk() Nombre d'lments dans la rgion stocks sur disque

long getSizeInMemory() Nombre d'octets consomms en mmoire par la rgion

Map getEntries() Obtenir les lments contenus dans la rgion du cache

Il est prfrable de mettre la valeur true la proprit hibernate.cache.use_structured_entries si la mthode getEntries() est utilise.

Exemple :

01. Statisticsstats=sessionFactory.getStatistics();
02. SecondLevelCacheStatisticscacheStats=stats
03. .getSecondLevelCacheStatistics("com.jmdoudoux.test.hibernatecache.entity.Pays");
04. System.out.println(cacheStats.getElementCountInMemory());
05. System.out.println(cacheStats.getElementCountOnDisk());
06. System.out.println(cacheStats.getEntries());
07. System.out.println(cacheStats.getHitCount());
08. System.out.println(cacheStats.getMissCount());
09. System.out.println(cacheStats.getPutCount());
10. System.out.println(cacheStats.getSizeInMemory());

Il est possible d'exposer les statistiques via JMX en utilisant un Mbean de type StatisticsServiceMBean. Il suffit d'enregistrer dans le serveur de
Mbeans une instance de type StatisticsService. Sa mthode setSessionFactory() permet de fournir en paramtre la SessionFactory dont les
statistiques doivent tre exposes.

Exemple :

1. MBeanServermBeanServer=ManagementFactory.getPlatformMBeanServer();
2. ObjectNameobjName=newObjectName("Hibernate:application=Statistics");
https://www.jmdoudoux.fr/java/dej/chaphibernate.htm 103/105
24/04/2017 DvelopponsenJavaHibernate
2. ObjectNameobjName=newObjectName("Hibernate:application=Statistics");
3. StatisticsServicestatsMBean=newStatisticsService();
4. statsMBean.setSessionFactory(sessionFactory);
5. statsMBean.setStatisticsEnabled(true);
6. mBeanServer.registerMBean(statsMBean,objName);

54.13. Les outils de gnration de code


Hibernate fournit sparment un certain nombre d'outils. Ces outils sont livrs dans un fichier nomm hibernate-extensions-2.1.zip.

Il faut tlcharger et dcompresser le contenu de cette archive par exemple dans le rpertoire o Hibernate a t dcompress.

L'archive contient deux rpertoires:

hibern8ide
tools

Le rpertoire tools propose trois outils:

class2hbm:
ddl2hbm:
hbm2java:

Pour utiliser ces outils, il y a deux solutions possibles:

utiliser les fichiers de commandes .bat fournis dans le rpertoire /tools/bin


utiliser ant pour lancer ces outils

Pour utiliser les fichiers de commandes .bat, il est ncessaire au pralable de configurer les paramtres dans le fichier setenv.bat. Il faut notamment
correctement renseigner les valeurs associes aux variables JDBC_DRIVER qui prcise le pilote de la base de donnes et HIBERNATE_HOME qui
prcise le rpertoire o est install Hibernate.

Pour utiliser les outils dans un script ant, il faut crer ou modifier un fichier build en ajoutant une tche pour l'outil utiliser.

Il faut copier le fichier hibernate2.jar et les fichiers contenus dans le rpertoire /lib d'Hibernate dans le rpertoire lib du projet. Il faut aussi copier
dans ce rpertoire les fichiers contenus dans le rpertoire /tools/lib et le fichier /tools/hibernate-tools.jar.

Pour viter les messages d'avertissement sur la configuration manquante de log4j, le plus simple est de copier le fichier /src/log4j.properties
d'Hibernate dans le rpertoire bin du projet.

Hibernate permet aussi de crer la structure du schma d'une base de base de donnes en utilisant la configuration du mapping des entits grce un
outil nomm hbm2ddl.

Il faut utiliser la proprit hibernate.hbm2ddl.auto qui peut prendre plusieurs valeurs :

validate: valider la structure du schma sans faire de modification dans la base de donnes
update: mettre jour le schma
create: crer le schma en supprimant celui existant
create-drop: crer le schma et le supprimer lorsque la sessionFactory est ferme

Exemple :

1. <hibernateconfiguration>
2.
3. <sessionfactory>
4. ...
5. <propertyname="hbm2ddl.auto">create</property>
6. ...
7. </sessionfactory>
8. </hibernateconfiguration>

Lorsque les valeurs create et create-drop sont utilises, il est possible de demander Hibernate d'initialiser des donnes dans le schma cr. Par
dfaut, Hibernate recherche un fichier import.sql dans le classpath. Si celui-ci est trouv, Hibernate excute les ordres SQL qu'il contient.

Depuis la version 3.6 d'Hibernate, la proprit hibernate.hbm2ddl.import_files permet de prciser un ou plusieurs fichiers qui seront utiliss pour crer
les donnes. Si plusieurs fichiers sont indiqus, il faut les sparer avec un caractre virgule. Ils seront excuts dans leur ordre de dfinition.

Exemple :

1. <hibernateconfiguration>
2. <sessionfactory>
3. ...
4. <propertyname="hbm2ddl.auto">create</property>
5. <propertyname="hbm2ddl.import_files">/importdonnees1.sql,/importdonnees2.sql</property>
6. ...
7. </sessionfactory>
8. </hibernateconfiguration>

https://www.jmdoudoux.fr/java/dej/chaphibernate.htm 104/105
24/04/2017 DvelopponsenJavaHibernate

Rsultat :

01. INFO:org.hibernate.tool.hbm2ddl.SchemaExport
02. Runninghbm2ddlschemaexport
03. INFO:org.hibernate.tool.hbm2ddl.SchemaExport
04. exportinggeneratedschematodatabase
05. INFO:org.hibernate.tool.hbm2ddl.SchemaExport
06. Executingimportscript:/importdonnees1.sql
07. INFO:org.hibernate.tool.hbm2ddl.SchemaExport
08. Executingimportscript:/importdonnees2.sql
09. INFO:org.hibernate.tool.hbm2ddl.SchemaExport
10. schemaexportcomplete

Cette fonctionnalit est particulirement utile pour des tests automatiss mais n'est pas recommande en production quand la gestion des volutions du
schma doit tre effectue de manire plus attentive.

La suite de ce chapitre sera dveloppe dans une version future de ce document


Dveloppons en Java v 2.10
Copyright (C) 1999-2016 Jean-Michel DOUDOUX.

https://www.jmdoudoux.fr/java/dej/chaphibernate.htm 105/105