Plan de la partie 2 (1) JPA 2 -...

44
1 JPA 2.0 (Java Persistence API) - Partie 2 - Partie 2 Université de Nice - Sophia Antipolis Version 2.6 – 28/1/10 Richard Grin Plan de la partie 2 (1) Récupérer des données de la base Langage d’interrogation JPQL API « Critère » Modifications en volume R. Grin JPA page 2 Exceptions Transaction Concurrence Entités détachées Plan de la partie 2 (2) Configuration d’une unité de persistance Fichiers de configuration XML JPA et DAOs Cache des données R. Grin JPA page 3 Cache des données Optimisation Méthodes callbacks et écouteurs Génération du schéma de la base de données Récupérer des données de la base de données R. Grin JPA page 4 de la base de données Cette section montre comment interroger la base de données pour récupérer des entités (des employés par exemple) ou des simples valeurs (des noms d’employés ou le total des R. Grin JPA page 5 salaires des employés par exemple) Rappel important Toutes les entités retrouvées par find, getReference ou un query sont automatiquement gérées par le gestionnaire d’entités Les modifications apportées à ces entités sont R. Grin JPA page 6 Les modifications apportées à ces entités sont donc enregistrées au prochain commit (mais les nouveaux objets associés à l’entité retrouvée ne sont pas automatiquement persistants même s'il y a une cascade sur persist ; ça ne marche que pour un appel explicite de la méthode persist)

Transcript of Plan de la partie 2 (1) JPA 2 -...

Page 1: Plan de la partie 2 (1) JPA 2 - unice.frdeptinfo.unice.fr/.../minfo/modpersobj/supports/jpa2-2-6.pdf1 JPA 2.0 (Java Persistence API) - Partie 2Partie 2 Université de Nice - Sophia

1

JPA 2.0(Java Persistence API)

- Partie 2- Partie 2Université de Nice - Sophia Antipolis

Version 2.6 – 28/1/10Richard Grin

Plan de la partie 2 (1)

Récupérer des données de la baseLangage d’interrogation JPQLAPI « Critère »Modifications en volume

R. Grin JPA page 2

Modifications en volumeExceptionsTransactionConcurrenceEntités détachées

Plan de la partie 2 (2)

Configuration d’une unité de persistanceFichiers de configuration XMLJPA et DAOsCache des données

R. Grin JPA page 3

Cache des donnéesOptimisationMéthodes callbacks et écouteursGénération du schéma de la base de données

Récupérer des données de la base de données

R. Grin JPA page 4

de la base de données

Cette section montre comment interroger la base de données pour récupérer des entités (des employés par exemple) ou des simples valeurs (des noms d’employés ou le total des

R. Grin JPA page 5

salaires des employés par exemple)

Rappel importantToutes les entités retrouvées par find, getReference ou un query sont automatiquement gérées par le gestionnaire d’entitésLes modifications apportées à ces entités sont

R. Grin JPA page 6

Les modifications apportées à ces entités sont donc enregistrées au prochain commit (mais les nouveaux objets associés à l’entité retrouvée ne sont pas automatiquement persistants même s'il y a une cascade sur persist ; ça ne marche que pour un appel explicite de la méthode persist)

Page 2: Plan de la partie 2 (1) JPA 2 - unice.frdeptinfo.unice.fr/.../minfo/modpersobj/supports/jpa2-2-6.pdf1 JPA 2.0 (Java Persistence API) - Partie 2Partie 2 Université de Nice - Sophia

2

Chercher par identité

find et getReference (de EntityManager) permettent de retrouver une entité en donnant son identificateur dans la BD<T> T find(Class<T> classeEntité, Obj t léP i i )

R. Grin JPA page 7

Object cléPrimaire)<T> T getReference(Class<T> classeEntité, Object cléPrimaire)Le résultat est null si aucune entité n’a cet identificateur dans la base de donnée

Exemple

Departement dept =em.find(Departement.class, 10);

R. Grin JPA page 8

getReference

getReference renvoie une référence vers une entité, sans que cette entité ne soit nécessairement initialiséeLe plus souvent il vaut mieux utiliser find

R. Grin JPA page 9

getReference

getReference peut être (rarement) utilisée pour améliorer les performances quand une entité non initialisée peut être suffisante, sans que l’entité entière soit retrouvée dans la base d d é

R. Grin JPA page 10

de donnéesPar exemple, pour indiquer une association dont le but est unique (OneToOne ou ManyToOne) :Departement dept =em.getReference(Departement.class, 10);

Employe emp.setDepartement(dept);

Interroger la base de donnéesIl est possible de rechercher des données sur des critères plus complexes que la simple identitéRemarque : dans toute la partie à venir sur les requêtes (query JPQL API criteria)

R. Grin JPA page 11

les requêtes (query, JPQL, API criteria), « entité » peut désigner une entité ou une classe (ou instance de) Embeddable ; depuis JPA 2.0, les classes Embeddable ont les « mêmes droits » que les classes entités

Étapes pour récupérer des données1. Décrire ce qui est recherché (langage JPQL

ou criteria API)2. Créer une instance de type Query3. Initialiser la requête (paramètres, pagination)

R. Grin JPA page 12

4. Lancer l’exécution de la requête

Page 3: Plan de la partie 2 (1) JPA 2 - unice.frdeptinfo.unice.fr/.../minfo/modpersobj/supports/jpa2-2-6.pdf1 JPA 2.0 (Java Persistence API) - Partie 2Partie 2 Université de Nice - Sophia

3

Description de la requête

Le langage JPQL (Java Persistence QueryLanguage) permet de décrire ce que l’application recherche (voir prochaine section)Il ressemble beaucoup à SQL :

R. Grin JPA page 13

select e from Employe e where e.nom = 'Dupond'

L’API « Criteria » a été introduite par JPA 2.0 pour décrire la requête d’une façon plus sûre, vérifiée à la compilation (étudiée à la suite de JPQL)

Requêtes sur les entités « objet »

Les requêtes JPQL ou « criteria » travaillent avec le modèle objet et pas avec le modèle relationnelLes identificateurs désignent les entités et leurs attributs et pas les tables et leurs colonnes

R. Grin JPA page 14

Les seules classes qui peuvent être explicitement désignées (par leur nom) dans une requête sont les entités et les classes « Embeddable »Rappel : le nom est donné par l’attribut @name de @Entity ou @Embeddable, ou, par défaut, par le nom de la classe

Type du résultat

L’expression renvoyée peut être n une (ou plusieurs) expression « entité »,

par exemple un employé (e par exemple)n une (ou plusieurs) expression « valeur »,

R. Grin JPA page 15

par exemple le nom d’un employé (e.nom), y compris une expression arithmétique (e.salaire * 1.25)

L’expression ne peut pas être une collection (d.employes par exemple), bien que certains fournisseurs de persistance le permettent !

Query

Pour faire exécuter la requête il faut créer un Query, instance qui représente une requête (étudiée en détails un peu plus loin)Plusieurs méthodes de EntityManager

’permettent d’obtenir un Query, suivant la façon dont la requête a été décrite

R. Grin JPA page 16

Méthodes pour obtenir un Query

Les méthodes suivantes de EntityManagerrenvoient un Query ; elles sont liées au langage JPQL, à l’API « criteria », aux requêtes natives SQL et aux requêtes nommées (tout

l ét dié d l it d )cela sera étudié dans la suite du cours)createQuery(String jpql)createQuery(CriteriaQuery criteria)createNativeQuery(String sql)createNamedQuery(String nom)

R. Grin JPA page 17

Exécuter une requête (1)

Plusieurs méthodes de l’interface Querypermettent d’exécuter une requête et de récupérer son résultat

R. Grin JPA page 18

Page 4: Plan de la partie 2 (1) JPA 2 - unice.frdeptinfo.unice.fr/.../minfo/modpersobj/supports/jpa2-2-6.pdf1 JPA 2.0 (Java Persistence API) - Partie 2Partie 2 Université de Nice - Sophia

4

Exécuter une requête (2)

Pour le cas où une seule valeur ou entité est renvoyée, le plus simple est d’utiliser la méthode getSingleResult() ; elle renvoie un ObjectLa méthode lance des exceptions s’il n’y a

R. Grin JPA page 19

La méthode lance des exceptions s il n y a pas exactement une entité qui correspond à la requête :n EntityNotFoundExceptionn NonUniqueResultException

Exécuter une requête (3)

Si plusieurs valeurs ou entités peuvent être renvoyées, il faut utiliser la méthode getResultList() de l’interface QueryElle renvoie une liste « raw » (pas générique) des résultats instance de java util List

R. Grin JPA page 20

des résultats, instance de java.util.List, éventuellement vide si le résultat est videUn message d’avertissement est affiché durant la compilation si le résultat est rangé dans une liste générique (List<Employe>par exemple)

Type d’un élément du résultat

Le type d’un élément de la liste (ou de l’unique valeur ou entité renvoyée) estn Object si la clause select ne comporte

R. Grin JPA page 21

j pqu’une seule expression

n Object[] si elle comporte plusieurs expressions

Exemple 1 : renvoie une entité

String s = "select e from Employe as e"; Query query = em.createQuery(s); List<Employe> listeEmployes = (List<Employe>)query.getResultList();

R. Grin JPA page 22

On peut faire un cast

Exemple 2 : renvoie une propriété

String s = "select e.nom from Employe as e";

Query query = em.createQuery(s); List<String> listeEmployes = (List<String>)query getResultList();

R. Grin JPA page 23

(List<String>)query.getResultList();

On peut faire un cast

Exemple 3 : renvoie plusieurs valeurs

texte = "select e.nom, e.salaire " + " from Employe as e";

query = em.createQuery(texte);List<Object[]> liste = (List<Object[]>)query getResultList();

R. Grin JPA page 24

(List<Object[]>)query.getResultList();for (Object[] info : liste) {System.out.println(info[0] + " gagne "

+ info[1]);}

Page 5: Plan de la partie 2 (1) JPA 2 - unice.frdeptinfo.unice.fr/.../minfo/modpersobj/supports/jpa2-2-6.pdf1 JPA 2.0 (Java Persistence API) - Partie 2Partie 2 Université de Nice - Sophia

5

Méthodes de Query (1)

List getResultList()Object getSingleResult()int executeUpdate()Query setMaxResults(int

R. Grin JPA page 25

Q y (nbResultats)Query setFirstResult(intpositionDepart)Query setFlushMode(FlushModeTypemodeFlush)

Méthodes de Query (2)

Query setParameter(String nom, Object valeur)Query setParameter(String nom, Date valeur, TemporalType

R. Grin JPA page 26

typeTemporel)Query setParameter(String nom, Calendar valeur, TemporalType typeTemporel)

Types temporels

On a vu que les 2 types java temporels du paquetage java.util (Date et Calendar) nécessitent une annotation @TemporalIls nécessitent aussi un paramètre

R. Grin JPA page 27

supplémentaire pour la méthode setParameter

Exemple

@Temporal(TemporalType.DATE)private Calendar dateEmb;em.createQuery("select e from employe e"+ " where e.dateEmb between ?1 and ?2").setParameter(1, debut, TemporalType.DATE)

R. Grin JPA page 28

p yp.setParameter(2, fin, TemporalType.DATE).getResultList();

Types de requêteRequête dynamique dont le texte JPQL est donné en paramètre de createQueryRequête native (ou requête SQL) particulière à un SGBD ou trop complexe pour JPA ; requête SQL (pas JPQL) avec tables et colonnes (pas

R. Grin JPA page 29

SQL (pas JPQL) avec tables et colonnes (pas classes et attributs) ; createNativeQueryRequête nommée dont le texte est donné statiquement dans une annotation d’une entité et dont le nom est passé en paramètre de createNamedQuery ; une requête nommée peut être écrite en JPQL ou en SQL (native)

Paramètres des requêtes

Un paramètre peut être désigné par son numéro (?n) ou par son nom (:nom)Les valeurs des paramètres sont données par les méthodes setParameter

R. Grin JPA page 30

Les paramètres sont numérotés à partir de 1Un paramètre peut être utilisé plus d’une fois dans une requêteL’usage des paramètres nommés est recommandé (plus lisible)

Page 6: Plan de la partie 2 (1) JPA 2 - unice.frdeptinfo.unice.fr/.../minfo/modpersobj/supports/jpa2-2-6.pdf1 JPA 2.0 (Java Persistence API) - Partie 2Partie 2 Université de Nice - Sophia

6

Requête nommée (1)

Seules les entités peuvent contenir des définitions de requêtes nomméesUne requête nommée peut être mise dans n’importe quelle entité, mais on choisira le

R. Grin JPA page 31

plus souvent l’entité qui correspond à ce qui est renvoyé par la requêteLe nom de la requête nommée doit être unique parmi toutes les entités de l’unité de persistance ; on pourra, par exemple, préfixer le nom par le nom de l’entité : Employe.findAll

Requête nommée (2)

Les requêtes nommées peuvent être analysée et précompilées par le fournisseur de persistance au démarrage de l’application, ce qui peut améliorer les performances

’ éf

R. Grin JPA page 32

L’annotation @NamedQuery définit une requête nommée écrite en JPQLL’annotation @NamedNativeQuery définit une requête nommée écrite en SQL (native)

Exemple de requête nommée@Entity@NamedQuery (name="findNomsEmployes",query="select e.nom from Employe as e where upper(e.departement.nom) = :nomDept"

R. Grin JPA page 33

)public class Employe extends Personne {...

Query q = em.createNamedQuery("findNomsEmployes");

Exemples

Query query = em.createQuery("select e from Employe as e "+ "where e.nom = ?1");

query.setParameter(1, "Dupond");Query query = em.createQuery(

R. Grin JPA page 34

y q y y"select e from Employe as e "+ "where e.nom = :nom");

query.setParameter("nom", "Dupond");

Plusieurs requêtes nommées

Si une classe a plusieurs requêtes nommées, il faut les regrouper dans une annotation @NamedQueries :@NamedQueries({@NamedQuery( )

R. Grin JPA page 35

@NamedQuery(...),@NamedQuery(...),...

})

Mapping pour requêtes natives (1)

Il est nécessaire de donner des informations sur les colonnes renvoyées par la requête SQL afin que le gestionnaire d’entités sache si elle correspondent à des entitésDans le cas où toutes les colonnes correspondent aux attributs d’une entité ces informations de mapping sont indiquées en donnant la classe de l’entité en paramètre de createNativeQuery

R. Grin JPA page 36

Page 7: Plan de la partie 2 (1) JPA 2 - unice.frdeptinfo.unice.fr/.../minfo/modpersobj/supports/jpa2-2-6.pdf1 JPA 2.0 (Java Persistence API) - Partie 2Partie 2 Université de Nice - Sophia

7

Mapping pour requêtes natives (2)

Dans les autres cas, une annotation @SqlResultSetMapping est nécessaireElle doit être ajoutée à une entité quelconqueCette annotation a un nom qui doit être passé q pen paramètre à la méthode createNativeQuery

Consultez une documentation sur JPA pour en savoir plus

R. Grin JPA page 37

Requêtes natives ou JDBC ?

Si une entité est renvoyée par la requête, il vaut mieux utiliser une requête native car le gestionnaire d’entités gérera l’entité comme les autres entitésSi des valeurs scalaires sont renvoyées, le choix est moins clair ; utiliser une requête nommée permettra de rester dans JPAUne requête trop complexe nécessitera JDBC ; de même si le texte de la requête est généré lors de l’exécution

R. Grin JPA page 38

Mode de flushNormalement (mode FlushMode.AUTO) un flush des entités concernées par une requête est effectué avant la requête pour que le résultat tienne compte des modifications effectuées en mémoire sur ces entités

R. Grin JPA page 39

Pour une requête il est possible d'éviter ce flush avec la méthode setFlushMode :query.setFlushMode(FlushMode.COMMIT);Dans ce mode, seul un commit provoquera un flush

Pagination du résultat

Query setMaxResults(int n) : indique le nombre maximum de résultats à retrouverQuery setFirstResult(int n) : indique la position du 1er résultat à retrouver

R. Grin JPA page 40

(numéroté à partir de 0)

Enchaînement des méthodes

Les méthodes setParameter, setMaxResults renvoient le Query modifiéOn peut donc les enchaînerExemple :

R. Grin JPA page 41

pem.createQuery(texteQuery).setParameter(nomParam, valeurParam).setFirstResult(30 * i + 1).setMaxResults(30).getResultList();

Langage JPQL –J P i t Q L

R. Grin JPA page 42

Java Persistence Query Language

Page 8: Plan de la partie 2 (1) JPA 2 - unice.frdeptinfo.unice.fr/.../minfo/modpersobj/supports/jpa2-2-6.pdf1 JPA 2.0 (Java Persistence API) - Partie 2Partie 2 Université de Nice - Sophia

8

Exemples de requêtes JPQL

select e from Employe as eselect e.nom, e.salaire from Employe eselect e from Employe e where e.departement.nom = 'Direction'select d nom avg(e salaire)

R. Grin JPA page 43

select d.nom, avg(e.salaire) from Departement d join d.employes e group by d.nomhaving count(d.nom) > 5

Alias

Le texte des requêtes utilise les alias de classe : « select e from Employe as e »Les attributs des classes doivent être préfixés par les alias : « e.nom »

R. Grin JPA page 44

Une erreur fréquente du débutant est d’oublier les alias en préfixe

Clauses d’un select

select : type des objets ou valeurs renvoyéesfrom : où les données sont récupéréeswhere : sélectionne les données

R. Grin JPA page 45

group by : regroupe des donnéeshaving : sélectionne les groupes (ne peut exister sans clause group by)order by : ordonne les données

Les mots-clés select, from, distinct, join,… sont insensibles à la casse

R. Grin JPA page 46

Polymorphisme dans les requêtes (1)

Toutes les requêtes sont polymorphes : un nom de classe dans la clause from désigne cette classe et toutes les sous-classesExemple :

R. Grin JPA page 47

select count(a) from Article as acompte le nombre d’instances de la classe Article et de tous les sous-classes de Article

Depuis JPA 2 on peut restreindre à un type donné : select a from Article where type(a)

Polymorphisme dans les requêtes (2)

Depuis JPA 2 on peut restreindre à un type donné :select a from Article a where type(a) in (Stylo, Lot)

R. Grin JPA page 48

Page 9: Plan de la partie 2 (1) JPA 2 - unice.frdeptinfo.unice.fr/.../minfo/modpersobj/supports/jpa2-2-6.pdf1 JPA 2.0 (Java Persistence API) - Partie 2Partie 2 Université de Nice - Sophia

9

Expression de chemin

Les requêtes peuvent contenir des expressions de chemin pour naviguer entre les entités en suivant les associations déclarées dans le modèle objet (les annotations @O T O @O T M )

R. Grin JPA page 49

annotations @OneToOne, @OneToMany, …)La notation « pointée » est utilisée

Règle pour les expressions de chemin

Une navigation peut être chaînée à une navigation précédente à la condition que la navigation précédente ne donne qu’une seule

R. Grin JPA page 50

navigation précédente ne donne qu une seule entité (OneToOne ou ManyToOne)Dans le cas où une navigation aboutit à plusieurs entités, il est possible d’utiliser la clause join étudiée plus loin pour obtenir ces entités

ExemplesSi e est un alias pour Employe, n « e.departement » désigne le

département d’un employén « e.projets » désigne la collection de

projets auxquels participe un employé

R. Grin JPA page 51

p j q p p p yselect e.nomfrom Employe as ewhere e.departement.nom = 'Qualité'

e.projets.nom n’est pas autorisé car e.projets est une collection (voir clause join)

Autre exemple

select e.nom,e.departement.nom,e.superieur.departement.nom

from Employe e

R. Grin JPA page 52

distinct

Dans une clause select, indique que les valeurs dupliquées sont éliminées (la requête ne garde qu’une seule des valeurs égales)Exemple :

R. Grin JPA page 53

select distinct e.departementfrom Employe e

new

Il est possible de renvoyer des instances d’une classe dont le constructeur prend en paramètre des informations récupérées dans la base de données

R. Grin JPA page 54

La classe doit être désignée par son nom complet (avec le nom du paquetage)Exemple :select new p1.p2.Classe(e.nom, e.salaire)from Employe e

Page 10: Plan de la partie 2 (1) JPA 2 - unice.frdeptinfo.unice.fr/.../minfo/modpersobj/supports/jpa2-2-6.pdf1 JPA 2.0 (Java Persistence API) - Partie 2Partie 2 Université de Nice - Sophia

10

Clauses where et having

Ces clauses peuvent comporter les mots-clés suivants :n [NOT] LIKE, [NOT] BETWEEN, [NOT] INn AND, OR, NOT

R. Grin JPA page 55

n [NOT] EXISTSn ALL, SOME/ANYn IS [NOT] NULLn IS [NOT] EMPTY, [NOT] MEMBER OF (pour

les collections)

Exemple

select d.nom, avg(e.salaire)from Departement d join d.employes egroup by d.nomhaving count(d.nom) > 3

R. Grin JPA page 56

having

Restriction : la condition doit porter sur l’expression de regroupement ou sur une fonction de regroupement portant sur l’expression de regroupement

R. Grin JPA page 57

Par exemple, la requête suivante provoque une exception :select d.nom, avg(e.salaire)from Departement d join d.employes egroup by d.nomhaving avg(e.salaire) > 1000

Sous-requête (1)

Les clauses where et having peuvent contenir des sous-requêtesExemple :select e from Employe eh l i > (

R. Grin JPA page 58

where e.salaire >= (select e2.salaire from Employe e2where e2.departement = 10)

Sous-requête (2)

{ALL | ANY | SOME} (sous-requête) fonctionne comme dans SQLExemple :select e from Employe eh l i > ALL (

R. Grin JPA page 59

where e.salaire >= ALL (select e2.salaire from Employe e2where e2.departement =

e.departement)

Sous-requête synchronisée

Une sous-requête peut être synchronisée avec une requête englobanteExemple :select e from Employe eh l i > ALL (

R. Grin JPA page 60

where e.salaire >= ALL (select e2.salaire from Employe e2where e2.departement =

e.departement)

Page 11: Plan de la partie 2 (1) JPA 2 - unice.frdeptinfo.unice.fr/.../minfo/modpersobj/supports/jpa2-2-6.pdf1 JPA 2.0 (Java Persistence API) - Partie 2Partie 2 Université de Nice - Sophia

11

Sous-requête - exists

[not]exists fonctionne comme avec SQLExemple :select emp from Employe ewhere exists (select ee from Employe ee

R. Grin JPA page 61

select ee from Employe eewhere ee = e.epouse)

Utilité de la jointure

« d.employes.nom » est interdit car d.employes est une collectionPour avoir les noms des employés d’un département, il faut utiliser une jointure

R. Grin JPA page 62

Jointure

Une jointure permet de combiner plusieurs entités dans un selectRappel : il est aussi possible d’utiliser plusieurs entités dans une requête grâce à la

i ti

R. Grin JPA page 63

navigationUne jointure est le plus souvent utilisée pour résoudre les cas (interdit par JPA) oùn l’expression du select serait une collectionn la navigation partirait d’une collection

Types de jointures

Il existe plusieurs types de jointures :n jointure interne (jointure standard join)n jointure externe (outer join)n jointure avec récupération de données en

R. Grin JPA page 64

j pmémoire (join fetch)

n jointure « à la SQL » dans un where pour joindre suivant des champs qui ne correspondent pas à une association (where e1.f1 = e2.f2)

Exemple

Si on veut tous les employés d’un département, la requête suivante n’est pas permise par la spécification JPAUne jointure est nécessaire :

R. Grin JPA page 65

select efrom Departement d join d.employes ewhere d.nom = 'Direction'

Autres exemplesselect e.nomfrom Departement d

join d.employes ewhere d.nom = 'Direction'select e.nom, parts.projet.nomfrom Employe e

join e participations parts

R. Grin JPA page 66

join e.participations parts select e.nom, d.nomfrom Employe e, Departement dwhere d = e.departementselect e, pfrom Employe e join e.participations partsjoin parts.projet p

Page 12: Plan de la partie 2 (1) JPA 2 - unice.frdeptinfo.unice.fr/.../minfo/modpersobj/supports/jpa2-2-6.pdf1 JPA 2.0 (Java Persistence API) - Partie 2Partie 2 Université de Nice - Sophia

12

Jointure externe

select e, dfrom Employe e left join e.departement dramènera aussi les employés qui ne sont pas associés à un département

R. Grin JPA page 67

join fetch

Permet d’éviter le problème des « N + 1 selects »L’entité placé à droite de join fetch sera créée en mémoire en même temps que

R. Grin JPA page 68

l’entité de la clause selectLe select SQL généré sera une jointure externe qui récupérera les données de toutes les entités associées en même temps que les données des entités principales de la requête

Exemple

select efrom Employe e join fetch e.departement

Cette requête récupérera tous les employés mais, en plus, l’appel de la méthode getDepartement() ne provoquera aucune

R. Grin JPA page 69

getDepartement() ne provoquera aucune interrogation de la base de données puisque le « join fetch » aura déjà chargé tous les départements des employés

Exemple

String texteQuery ="select e "+ " from Employe as e " + " join fetch e.participations";

Q t Q (t t Q )

R. Grin JPA page 70

Query query = em.createQuery(texteQuery);listeEmployes = (List<Employe>)query.getResultList();

Cet exemple précharge les participations aux projets des employés

Doublons possibles avec join fetchLa requête SQL lancée par un join fetch fait une jointure pour récupérer les entités préchargéesEnsuite, les entités préchargées sont enlevées des lignes du résultat pour qu’elles n’apparaissent pas dans le résultat du queryC t it t i é l é ifi ti d

R. Grin JPA page 71

Ce traitement, imposé par la spécification de JPA, peut occasionner des doublons dans le résultat si le select renvoie des valeurs (pas des entités)Pour les éviter, il faut ajouter l’opérateur DISTINCT dans le texte de la requête ou placer le résultat dans une collection de type Set

Il existe aussi des variantes « outer join » de join fetch pour récupérer dans le select des entités non jointes à une autre entité

R. Grin JPA page 72

Page 13: Plan de la partie 2 (1) JPA 2 - unice.frdeptinfo.unice.fr/.../minfo/modpersobj/supports/jpa2-2-6.pdf1 JPA 2.0 (Java Persistence API) - Partie 2Partie 2 Université de Nice - Sophia

13

Produit cartésien (1)

Le préchargement par join fetch de plusieurscollections d’une même entité peut occasionner un phénomène nuisible aux performancesEn effet, le select SQL généré par le

R. Grin JPA page 73

fournisseur de persistance peut récupérer un produit cartésien des éléments des collectionsLe fournisseur s’arrange pour ne garder que les informations nécessaires mais le select peut renvoyer un très grand nombre de lignes qui vont transiter par le réseau

Produit cartésien (2)Dans le cas où les collections contiennent de nombreux éléments il faut donc vérifier avec les logs du fournisseur si le select généré renvoie effectivement un trop grand nombre de lignes et changer de stratégie de récupération si c’est le cas (récupérer séparément les informations

R. Grin JPA page 74

le cas (récupérer séparément les informations sur les collections)En effet, si 2 collections contiennent 20 éléments, et si 1000 entités principales sont renvoyées le select renverra 400.000 lignes ! (au lieu de 40.000 si on ramène les informations avec 2 join fetch séparés)

ExempleUne entité principale ep avec 2 associations de l’entité principale avec d’autres entités e2 et e3Pour récupérer en mémoire les entités principales et associées, le select généré risque d’être du type suivant (consulter les logs

R. Grin JPA page 75

q yp ( gdu fournisseur de persistance) :select ep.*, e2.*, e3.*from EP epleft outer join E2 e2 on ep.id_e2 =

e2.idleft outer join E3 e3 on ep.id_e3 =

e3.id

FonctionsPour les chaînes de caractères : concat, substring, trim, lower, upper, length, locate (localiser une sous-chaîne dans une autre)Arithmétiques : abs, sqrt, mod, size (d’une

ll ti )

R. Grin JPA page 76

collection)Pour les date : current_date, current_time, current_timestampDe regroupement : count, max, min, avg« Conditionnelles » : case, coalesce, nullifqui sont les pendants des fonctions SQL

caseJPA 2.0 a introduit le case de SQL (peut être utilisé dans une clause where ou having ou même dans un update (voir section suivante)Variante « simple » :CASE valeurWHEN valeur1 THEN résultat1WHEN valeur1 THEN résultat1WHEN valeur2 THEN résultat2…ELSE résultatN

ENDvaleur peut être un attribut ou une expression de type

R. Grin JPA page 77

case

Variante « généraleCASEWHEN condition1 THEN résultat1WHEN condition2 THEN résultat2…ELSE résultatN

END

R. Grin JPA page 78

Page 14: Plan de la partie 2 (1) JPA 2 - unice.frdeptinfo.unice.fr/.../minfo/modpersobj/supports/jpa2-2-6.pdf1 JPA 2.0 (Java Persistence API) - Partie 2Partie 2 Université de Nice - Sophia

14

Exemples de caseselect a.description,case type(a)when Stylo then 'stylo'when Ramette then 'ramette'else 'autre type'

endendfrom Article aupdate Employe eset e.salaire = case e.indicewhen 1 then e.salaire * 1.1else e.salaire * 1.2

endR. Grin JPA page 79

coalesce

coalesce(expression1, expression2,...)renvoie la valeur de la 1ère expression non égale à nullExemple : coalesce(commission, salaire, 0)renvoie la valeur de la commission si elle n’est pas null, sinon renvoie la valeur s’il n’est pas null, et renvoie 0 sinon

R. Grin JPA page 80

nullif

nullif(expression1, expression2) renvoie null si les 2 expressions sont égales, sinon renvoie la valeur de expression1Peut servir pour une ancienne base de données dans laquelle les valeurs « null » sont en fait représentées par une certaine valeurExemple : nullif(salaire, -1)

R. Grin JPA page 81

Fonction index

JPA 2.0 permet de conserver l’ordre d’une liste grâce à une colonne de la BDLa fonction index retourne la valeur de cette colonne (0 pour le 1er élément) Exemple :select e.nom, t.numerofrom Employe e join e.telephones twhere index(t) = 0affiche les noms des employés avec leur numéro de téléphone classé 1er dans la liste de leurs numéro de téléphone

R. Grin JPA page 82

Travail avec les collectionsUne expression chemin d’un select peut désigner une collectionExemples : departement.employesfacture.lignes

R. Grin JPA page 83

facture.lignesLa fonction size donne la taille de la collectionLa condition « is [not] empty » est vraie si la collection est [n’est pas] videLa condition « [not] member of » indique si une entité appartient à une collection

Exemples

select dfrom Departementwhere e.employes is emptyselect efrom Employe e

R. Grin JPA page 84

p ywhere :projet member of e.participations.projet

Page 15: Plan de la partie 2 (1) JPA 2 - unice.frdeptinfo.unice.fr/.../minfo/modpersobj/supports/jpa2-2-6.pdf1 JPA 2.0 (Java Persistence API) - Partie 2Partie 2 Université de Nice - Sophia

15

Parcours d’une collection

La requête suivante ne donnera pas tous les produits liés à une facture ; elle provoquera une exception à l’exécutionselect distinct f.lignes.produitfrom Facture as f

R. Grin JPA page 85

from Facture as f

En effet, il est interdit de composer une expression de chemin en partant d’une expression qui désigne une collection (f.lignes)

Parcours d’une collection

Le plus simple est d’utiliser un join dans le from avec un alias (« l » dans l’exemple ci-dessous) pour désigner un élément qui parcourt la collection :select distinct l produit

R. Grin JPA page 86

select distinct l.produitfrom Facture as f join f.lignes as l

L’autre solution, « in », une ancienne syntaxe héritée d’EJB 2, n’est pas recommandée

API « critères »

R. Grin JPA page 87

IntroductionAPI introduite par JPA 2.0Tout ce qui peut être fait avec JPQL peut l’être avec l’API « critères »Les requêtes JPQL sont des String qui

t t i d ( l lpeuvent contenir des erreurs (par exemple le nom d’une classe qui n’existe pas)L’avantage de l’API « critères » est que les requêtes peuvent être vérifiées à la compilationL’inconvénient est que le code est un peu plus complexe à écrire, et sans doute moins lisible

R. Grin JPA page 88

API complexe

L’API contient de nombreuses interfaces et ne peut être détaillée dans ce coursNous n’en donnerons qu’un aperçu avec un exemple simple qui est l’équivalent de l’ordre JPQL suivant :select efrom Employe ewhere e.nom = 'Dupond'

R. Grin JPA page 89

Sans le meta-modèle

CriteriaBuilder cb = em.getCriteriaBuilder();CriteriaQuery<Employe> criteria =

cb.createQuery(Employe.class);Root<Employe> emp = criteria.from(Employe.class);c.select(emp).

h ( b l( t(" ") "D d"))where(cb.equal(emp.get("nom"), "Dupond"));

R. Grin JPA page 90

Page 16: Plan de la partie 2 (1) JPA 2 - unice.frdeptinfo.unice.fr/.../minfo/modpersobj/supports/jpa2-2-6.pdf1 JPA 2.0 (Java Persistence API) - Partie 2Partie 2 Université de Nice - Sophia

16

Meta-modèle

On voit que des String (get("nom")) sont utilisées pour désigner les attributsDes erreurs ne pourront être détectées qu’à l’exécutionLe meta-modèle va permettre de sécuriser les requêtes en les faisant vérifier par le compilateurUne classe du meta-modèle décrit une classe persistante ; le compilateur peut l’utiliser pour vérifier une requête

R. Grin JPA page 91

Exemple de classe du meta-modèle

@StaticModel(Employe.class)public class Employe_ {

public static volatile SingularAttributes<Employe, Integer> id;

public static volatile SingularAttributes<Employe, String> nom;

public static volatile SingularAttributes<Employe, Departement> dept;

public static volatile CollectionAttributes<Employe, Projet> projets;

// D’autres « public static volatile ... »...

}R. Grin JPA page 92

Avec le meta-modèle

CriteriaBuilder cb = em.getCriteriaBuilder();CriteriaQuery<Employe> criteria =

cb.createQuery(Employe.class);Root<Employe> emp = criteria.from(Employe.class);c.select(emp).

h ( b l( t(E l ) "D d"))where(cb.equal(emp.get(Employe_.nom), "Dupond"));

R. Grin JPA page 93

Exemple plus complexeQueryBuilder qb = em.getQueryBuilder();Criteria q = qb.create();Root<Client> client = q.from(Client.class);Join<Facture,LigneFacture> ligne =

client.join(Client_.factures).join(Facture_.lignesFacture);

q.where(qb.equals(q (q q (ligne.get(ligne_.produit).get(Produit_.typeProduit),"imprimante")).select(client.get(Client_.nom));

R. Grin JPA page 94

select c.nomfrom Client c join c.factures f joinf.lignes lwhere l.produit.typeProduit = 'imprimante'

En JPQL :

Classes de métadonnées

Les noms de classe suffixés par « _ » sont des classes qui représentent les métadonnées sur les classes entitésCes classes peuvent être générées automatiquement au moment de la compilation, ou écrites par le développeur

R. Grin JPA page 95

Opérations de modification en volume

R. Grin JPA page 96

en volume

Page 17: Plan de la partie 2 (1) JPA 2 - unice.frdeptinfo.unice.fr/.../minfo/modpersobj/supports/jpa2-2-6.pdf1 JPA 2.0 (Java Persistence API) - Partie 2Partie 2 Université de Nice - Sophia

17

Utilité

Pour les performances il est parfois mauvais de charger toutes les données à modifier dans des instances d’entitésEn ce cas, JPQL permet de modifier les

R. Grin JPA page 97

données de la base directement, sans créer les entités correspondantes

Cas d’utilisationSi on veut augmenter de 5% les 1000 employés de l’entreprise il serait mauvais de récupérer dans 1000 instances les données de chaque employés, de modifier le salaire de chacun, puis de sauvegarder les données

R. Grin JPA page 98

de chacun, puis de sauvegarder les donnéesUn simple ordre SQLupdate employeset salaire = salaire * 1.05sera énormément plus performantJPQL permet de lancer cet ordre sans passer par JDBC

Exempleem.getTransaction().begin();String ordre =

"update Employe e " +" set e.salaire = e.salaire * 1.05";

Query q = em.createQuery(ordre);

R. Grin JPA page 99

int nbEntitesModif = q.executeUpdate(); em.getTransaction().commit();

SyntaxeLes ordres de modification en volume référencent les classes et les propriétés des classes mais ils ne créent aucune entité en mémoire et ils ne mettent pas à jour les entités déjà présentes en mémoire

R. Grin JPA page 100

j pupdate Entite as aliasset alias.prop1 = val1, alias.prop2 = val2,…where conditionLa condition peut être aussi complexe que la condition d’un select

RemarquesLes modifications doivent être faites dans une transactionLe plus souvent il faut isoler le lancement de ces opérations dans une transaction à part, ou au moins exécuter ces opérations au début

R. Grin JPA page 101

d’une transaction avant la récupération dans la base d’entités touchées par l’opérationEn effet, les entités en mémoire ne sont pas modifiées par l’opération et elles ne correspondront alors donc plus aux nouvelles valeurs modifiées dans la base de données

Version des entités

Les versions des entités modifiées par les modifications en volume ne sont pas nécessairement mises à jour (dépend des fournisseurs de persistance, donc pas

t bl )portable)Il peut donc être nécessaire d’incrémenter explicitement le numéro de version dans le update

R. Grin JPA page 102

Page 18: Plan de la partie 2 (1) JPA 2 - unice.frdeptinfo.unice.fr/.../minfo/modpersobj/supports/jpa2-2-6.pdf1 JPA 2.0 (Java Persistence API) - Partie 2Partie 2 Université de Nice - Sophia

18

Exceptions

R. Grin JPA page 103

Exceptions utilisées par JPA

JPA n’utilise que des exceptions non contrôlées (descendantes de RuntimeException)JPA utilise les 2 exceptions IllegalArgumentException et

R. Grin JPA page 104

IllegalStateException du paquetage java.lang

Sinon, toutes les autres exceptions sont dans le paquetage javax.persistence et héritent de PersistenceException

Types d’exception

NonUniqueResultExceptionNoResultExceptionEntityNotFoundExceptionEntityExistsException

R. Grin JPA page 105

y pTransactionRequiredExceptionRollbackExceptionOptimisticLockExceptionPessimisticLockExceptionLockTimeoutException

PersistenceException et rollbackToute les exceptions de type PersistenceException marquent la transaction en cours pour un rollback (voir section suivante sur les transactions), sauf NoResultException,

R. Grin JPA page 106

pNonUniqueResultException et LockTimeoutException

Exceptions dans les méthodes d’accès aux propriétés

Les RuntimeException marquent la transaction en cours pour un rollbackLes exception contrôlées sont enveloppées dans une PersistenceException (nondans une PersistenceException (non contrôlée) et la transaction en cours est marquée pour un rollback

R. Grin JPA page 107

Transaction

R. Grin JPA page 108

Page 19: Plan de la partie 2 (1) JPA 2 - unice.frdeptinfo.unice.fr/.../minfo/modpersobj/supports/jpa2-2-6.pdf1 JPA 2.0 (Java Persistence API) - Partie 2Partie 2 Université de Nice - Sophia

19

2 types de transactions

Les transactions locales à une ressource, fournies par JDBC sont attachées à une seule base de donnéesLes transactions JTA, ont plus de

R. Grin JPA page 109

fonctionnalités que les transactions JDBC ; en particulier elles peuvent travailler avec plusieurs bases de données

Transactions dans Java EE

Elles ne sont pas étudiées dans ce cours

R. Grin JPA page 110

Transactions dans Java SE(sans serveur d’applications)

D’après la spécification JPA, dans Java SE, les fournisseurs de persistance doivent supporter les transactions locales à une ressource mais ne sont pas obligés de

R. Grin JPA page 111

ressource, mais ne sont pas obligés de supporter les transactions JTALa démarcation des transactions est choisie par le développeurLes contextes de persistance peuvent couvrir plusieurs transactions

EntityTransaction

En dehors d’un serveur d’applications, une application doit utiliser l’interface javax.persitence.EntityTransactionpour travailler avec des transactions locales à

R. Grin JPA page 112

une ressourceUne instance de EntityTransaction peut s’obtenir par la méthode getTransaction()de EntityManager

EntityTransaction

public interface EntityTransaction {public void begin();public void commit();public void rollback();bli id tR llb kO l ()

R. Grin JPA page 113

public void setRollbackOnly();public boolean getRollbackOnly();public boolean isActive();

}

Exemple

EntityManager em;...try {em.getTransaction().begin()

R. Grin JPA page 114

...em.getTransaction().commit();

}finally {em.close();

}

Page 20: Plan de la partie 2 (1) JPA 2 - unice.frdeptinfo.unice.fr/.../minfo/modpersobj/supports/jpa2-2-6.pdf1 JPA 2.0 (Java Persistence API) - Partie 2Partie 2 Université de Nice - Sophia

20

Rollback (1)

En cas de rollback,n rollback dans la base de donnéesn le contexte de persistance est vidé ; toutes

les entités deviennent détachées

R. Grin JPA page 115

Rollback (2)

Les instances d’entités Java gardent les valeurs qu’elles avaient au moment du rollbackMais ces valeurs sont le plus souvent faussesIl est donc rare d’utiliser ces entités en les

R. Grin JPA page 116

rattachant par un merge à un GELe plus souvent il faut relancer des requêtes pour récupérer des entités avec des valeurs correctes

Transaction et contexte de persistance

Quand un GE n’est pas géré par un container (c’est le cas en dehors d’un serveur d’applications) le contexte de persistance n’est pas fermé à la fin d’une transaction

R. Grin JPA page 117

n est pas fermé à la fin d une transactionQuand un GE est géré par un container (c’est le cas avec un serveur d’applications) et que le contexte de persistance n’est pas de type « étendu » (pas étudié dans ce cours), le contexte est fermé à la fin d’une transaction

Synchronisation d’un GE avec une transaction

Synchronisation d’un GE avec une transaction : le GE est enregistré auprès de la transaction ; un commit de la transaction provoquera alors automatiquement un flush du GE (le GE est

R. Grin JPA page 118

automatiquement un flush du GE (le GE est averti lors du commit)En dehors d’un serveur d’applications (avec Java SE), un GE est obligatoirement synchronisé avec les transactions (qu’il a lancées par la méthode begin() de EntityTransaction)

Modifications et commit

Les modifications effectuées sur les entités gérées sont enregistrées dans la base de données au moment d’un flush du contexte de persistanceSi le GE est synchronisé à la transaction en

R. Grin JPA page 119

Si le GE est synchronisé à la transaction en cours, le commit de la transaction enregistre donc les modifications dans la baseLes modifications sont enregistrées dans la base, même si elles ont été effectuées avant le début de la transaction (avant tx.begin()dans Java SE)

Erreurs et problèmes divers

Démarrer une nouvelle transaction alors qu’il y en a déjà une en cours lancera une IllegalStateExceptioncommit() et rollback() lancent la même exception si aucune transaction n’est activeSi une erreur survient lors de rollback(), une PersistanceException sera lancéeSi une erreur survient lors de commit(), une RollbackException est lancée

R. Grin JPA page 120

Page 21: Plan de la partie 2 (1) JPA 2 - unice.frdeptinfo.unice.fr/.../minfo/modpersobj/supports/jpa2-2-6.pdf1 JPA 2.0 (Java Persistence API) - Partie 2Partie 2 Université de Nice - Sophia

21

Marquage pour un rollback (1)

Dans les applications d’entreprise, les transactions sont souvent gérées par un serveur d’applications qui effectue lui-même les commit et rollbackLe code de l’application ne peut lancer de commit ou de rollback ; elle peut cependant marquer la transaction pour un rollback par la méthode setRollbackOnly()Le serveur d’applications sera alors obligé de terminer la transaction par un rollback

R. Grin JPA page 121

Marquage pour un rollback (2)

Le plus souvent la méthode setRollbackOnly est appelée dans un bloc catch lorsqu’une exception s’est produitePlus généralement elle peut être appelée lorsqu’une condition quelconque ne permet pas que la transaction soit validéeIl est impossible d’enlever une marque pour un rollback

R. Grin JPA page 122

Marquage pour un rollback (3)

Cette méthode (ainsi que la méthode getRollbackOnly) ne peut être appelée dans le cas où l’application gère elle-même les transactionsC’est le cas en particulier des applications qui ne sont pas gérées par un serveur d’applications ; ces 2 méthodes sortent donc du cadre fixé pour ce cours

R. Grin JPA page 123

Exceptions et transactions

Il faut prendre garde de ne pas laisser des transactions ouvertes dans le cas où des flushs ont transféré des commandes vers la base de donnéesEn effet, les blocages effectuées dans la base de données ne seront alors pas libérésUne cause d’erreur peut être la levée d’une exception qui fait sortir d’une méthode, et dont le traitement ne ferme pas la transaction en cours (par commit ou rollback)

R. Grin JPA page 124

Concurrence

R. Grin JPA page 125

GE et threads

Une fabrique de GE peut être utilisée sans problème par plusieurs threadsMais un GE ne doit être utilisé concurremment que par un seul thread

R. Grin JPA page 126

Page 22: Plan de la partie 2 (1) JPA 2 - unice.frdeptinfo.unice.fr/.../minfo/modpersobj/supports/jpa2-2-6.pdf1 JPA 2.0 (Java Persistence API) - Partie 2Partie 2 Université de Nice - Sophia

22

Entités et threads

Les entités ne sont pas prévues pour être utilisées par plusieurs threads en même tempsSi ça doit être le cas, l’application doit prendre toutes ses précautions pour éviter les problèmes

R. Grin JPA page 127

problèmesC’est aussi le rôle de l’application d’empêcher qu’une entité ne soit gérée par plusieurs GE en même tempsLe rôle du fournisseur de persistance n’intervient pas pour ces cas

Concurrence « BD »

Le fournisseur de persistance peut apporter automatiquement une aide pour éviter les problèmes d’accès concurrents aux données de la BD, pour les entités gérées par un GE

R. Grin JPA page 128

Exemple de problème de concurrence « BD »

Une entité est récupérée depuis la BD (par un find par exemple)L’entité est ensuite modifiée par l’application puis la transaction souhaite valider cette

R. Grin JPA page 129

pmodificationSi une autre transaction a modifié entre-temps les données de la BD correspondant à l’entité, la transaction ne doit pas être validée pour éviter les problèmes de mises à jour perdues

Gestion de la concurrence

Par défaut, le fournisseur de persistance gère les problèmes d’accès concurrents aux entités gérées par un GE avec une stratégie optimisteJPA suppose aussi que la BD a le mode

R. Grin JPA page 130

d’isolation « READ COMMITED » (voir cours sur les BD) et que les écritures dans la base n’ont lieu qu’au moment d’un flush

@Version

Annote un attribut dont la valeur représente un numéro de version (incrémenté à chaque modification), utilisé pour savoir si l’état d’une entité a été modifié entre 2 moments différentsL’attribut doit être de type int Integer

R. Grin JPA page 131

L attribut doit être de type int, Integer, short, Short, long, Long ou java.sql.TimeStamp (si possible, éviter ce dernier type) et ne doit pas être null dans la base de données

Modification de la versionL’application ne doit jamais modifier un tel attribut (seul JPA le modifie), sauf, éventuellement lors des opérations de modifications en volumeLa version est mise à jour automatiquement si le champ modifié est un champ « ordinaire » ou un

R. Grin JPA page 132

champ lié à une association dont l’entité possède la clé étrangère Si on veut mettre à jour la version dans le cas d’une association dont l’entité ne possède pas la clé étrangère, il faut utiliser lock avec l’option d’incrément de la version (étudié ci-après)

Page 23: Plan de la partie 2 (1) JPA 2 - unice.frdeptinfo.unice.fr/.../minfo/modpersobj/supports/jpa2-2-6.pdf1 JPA 2.0 (Java Persistence API) - Partie 2Partie 2 Université de Nice - Sophia

23

Exemple

@Versionprivate int version;

R. Grin JPA page 133

Entité « versionnée »

C’est une entité qui possède un attribut qui possède l’annotation @Version (ou le tag correspondant dans les fichiers XML)

R. Grin JPA page 134

Protection des entités « versionnées »

Les données de la BD correspondant à une entité versionnée ne peuvent être modifiées concurremment par 2 transactions gérées par JPA : si une transaction t1 récupère les

R. Grin JPA page 135

pdonnées, elle ne pourra valider des modifications sur ces données que si une autre transaction ne les a pas modifiées entre le moment où t1 les a lues et le moment où elle lance un commit

Protection des entités « non versionnées »

Le fournisseur de persistance peut aussi effectuer automatiquement ce contrôle sur une entité non versionnée (par exemple en comparant les données lues avec les

R. Grin JPA page 136

pdonnées de la base au moment du commit), mais JPA ne l’impose pasPour la portabilité il vaut donc mieux versionner les entités sujettes à des accès concurrents

lock(entite, mode)

Sert à protéger une entité contre les accès concurrents pour les cas où la protection offerte par défaut ne suffit pasCette entité doit être versionnée (sinon, le

R. Grin JPA page 137

traitement n’est pas portable) et déjà gérée

Situations à éviter

Les blocages de JPA ont pour rôle, au moins, d’éviter 2 situations bien connues de la théorie des accès concurrents par des transactionsn les lectures « sales » (dirty) : une valeur

modifiée par transaction non validée peut être lue par les autres transactions

n les lectures non répétables : une transaction lit 2 fois la même entité et l’état de cette entité a été modifiée par une autre transaction entre les 2 lectures

R. Grin JPA page 138

Page 24: Plan de la partie 2 (1) JPA 2 - unice.frdeptinfo.unice.fr/.../minfo/modpersobj/supports/jpa2-2-6.pdf1 JPA 2.0 (Java Persistence API) - Partie 2Partie 2 Université de Nice - Sophia

24

Modes de blocage

L’énumération LockModeType (paquetage javax.persistence) définit 5 modes n OPTIMISTIC (READ en JPA 1)n OPTIMISTIC_FORCE_INCREMENT (WRITE

R. Grin JPA page 139

_ _en JPA 1)

n PESSIMISTIC_READn PESSIMISTIC_WRITEn PESSIMISTIC_FORCE_INCREMENT

Modes de blocage optimistesOPTIMISTIC : permet une lecture répétable ; si une autre transaction modifie l’entité bloquée, la transaction qui a bloqué l’entité s’apercevra que le numéro de version a changé et sera invalidée

R. Grin JPA page 140

changé et sera invalidée OPTIMISTIC_FORCE_INCREMENT : comme OPTIMISTIC, mais en plus l’attribut de version est incrémenté, même si l’entité n’a pas été modifiée ) par la transaction dans laquelle le blocage a été effectué (utilité expliquée dans les transparents suivants

Utilité du blocage OPTIMISTICCe blocage est utile pour faire des bilans pour lesquels les données ne doivent pas être modifiées du début à la fin du traitementIl peut aussi être utile si 2 valeurs sont étroitement liées de telle sorte que la

R. Grin JPA page 141

étroitement liées de telle sorte que la modification d’une des valeurs par une transaction T empêche la modification de l’autre par une autre transaction ; pour modifier une des 2 valeurs, T doit alors bloquer aussi l’autre valeur, même si celle-ci ne sera pas modifiée par la transaction T

Blocage OPTIMISTICLa différence avec le mode de protection par défaut est que les 2 transactions ne seront pas validées, même si l’entité n’est pas modifiée par la transaction qui a bloqué l’entité

R. Grin JPA page 142

Blocage OPTIMISTIC

Le « blocage » réel peut n’être effectué qu’au moment du flush ou du commitS’il y a un problème, une exception OptimisticLockException peut être

R. Grin JPA page 143

lancée

Un exemple (1)Un bilan qui calcule le total des salaires des employés pour chaque département doit interdire qu’un employé ne change de département pendant le traitement, en passant du département 10 au département 20

R. Grin JPA page 144

p pSinon, cet employé sera compté 2 fois : après avoir fait le calcul du total du département 10, on va faire une requête pour récupérer les employés du département 20 et retrouver l’employé déjà décompté dans le département 10

Page 25: Plan de la partie 2 (1) JPA 2 - unice.frdeptinfo.unice.fr/.../minfo/modpersobj/supports/jpa2-2-6.pdf1 JPA 2.0 (Java Persistence API) - Partie 2Partie 2 Université de Nice - Sophia

25

Un exemple (2)

Pour éviter ce problème, les employés peuvent être bloqués en mode OPTIMISTIC, au fur et à mesure de leur prise en compte pour le calcul du total des salaires de leur dé t t

R. Grin JPA page 145

département

OPTIMISTIC_FORCE_INCREMENT

Force une incrémentation du numéro de versionPour certains traitements il est intéressant de considérer que l’entité a été modifiée même si aucun de ses attributs n’a été modifié, par

R. Grin JPA page 146

exemple lorsqu’une association avec une autre entité a été modifiéeDans l’exemple qui suit, le blocage OPTIMISTIC_FORCE_INCREMENT évite en quelque sorte les problèmes de lignes fantômes avec les associations qui concernent une entité

OPTIMISTIC_FORCE_INCREMENT

En effet, sans le blocage OPTIMISTIC_FORCE_INCREMENT (« OFI » pour la suite), le fournisseur de persistance incrémente automatiquement le numéro de

i i tité t difié i i

R. Grin JPA page 147

version si une entité est modifiée mais pas si les liens des associations qui partent de l’entité sont modifiées lorsque l’entité n’est pas propriétaire de l’association (voir cependant la remarque qui suit l’exemple donné dans les transparents suivants)

Utilité des blocages OFI (1)

Une en-tête de facture contient un champ dans lequel est stocké le total de la factureSupposons que le calcul de ce total est effectué par un processus à part du processus de l’ajout des lignes de la facture

R. Grin JPA page 148

de l ajout des lignes de la factureLorsqu’une ligne de facture est ajoutée à une facture, l’en-tête de la facture n’est pas modifiée donc le fournisseur de persistance n’incrémente pas le numéro de version de l’en-tête

Utilité des blocages OFI (2)

Une ligne peut être ajoutée à une facture sans que le traitement qui calcule le total ne s’en rende compte ; il y aura inconsistance entre ce total et les lignes de la factureSi l’en tête est bloquée en écriture pendant

R. Grin JPA page 149

Si l en-tête est bloquée en écriture pendant l’ajout d’une ligne de facture, le traitement qui effectue le calcul du total s’apercevra que la facture a changé pendant le calcul puisque le numéro de version aura été incrémenté et il n’y aura pas inconsistance

Remarque

Certains fournisseurs de persistance comme Hibernate incrémentent le numéro de version quand les collections d’une entité sont modifiées

R. Grin JPA page 150

Dans ce cas le blocage OFI sera tout de même utile si, par exemple, un des éléments de la collection est modifié, par exemple le prix d’un produit compris dans la facture

Page 26: Plan de la partie 2 (1) JPA 2 - unice.frdeptinfo.unice.fr/.../minfo/modpersobj/supports/jpa2-2-6.pdf1 JPA 2.0 (Java Persistence API) - Partie 2Partie 2 Université de Nice - Sophia

26

Blocages pessimistes (1/3)

Lorsque la probabilité de conflits est trop importante, la stratégie optimiste conduit à de trop nombreux rollbackEn ce cas il vaut mieux bloquer dès le début l’accès des autres transactions aux données que l’on manipuleJPA 2.0 a ajouté des blocages pessimistesComme les blocages optimistes, ils permettent d’éviter les lectures non répétables

R. Grin JPA page 151

Blocages pessimistes (2/3)

Le blocage dure jusqu’à la fin de la transactionAucune autre transaction du SGBD sous-jacent ne pourra modifier ou supprimer les données bloquéesSi le blocage est FORCE_INCREMENT ou WRITE, la transaction qui a bloqué pourra modifier ou supprimer les données bloquées (un blocage READ peut être partagé avec une autre transaction et donc empêcher la transaction de modifier les données)

R. Grin JPA page 152

Blocages pessimistes (3/3)

Les versions des entités bloquées en mode pessimiste et modifiées sont mises à jour

R. Grin JPA page 153

Portée du blocageL’énumération PessimisticLockScopecontient les 2 valeurs NORMAL et EXTENDEDEn mode EXTENDED, les données correspondant à une association ou à une collection d’éléments qui sont dans une tablecollection d éléments, qui sont dans une table jointe, sont aussi bloquéesLa portée peut être indiquée avec la propriété javax.persistence.lock.scope dans différentes méthodes des classes EntityManager et Query comme la méthode lock(entité, mode, propriétés)

R. Grin JPA page 154

Modes de blocage pessimistes

PESSIMISTIC_WRITE : le mode le plus courant ; les données de la base correspondant aux entités bloquées ne pourront être modifiées par d’autres t titransactionsPESSIMISTIC_READ : assure des lectures répétablesPESSIMISTIC_FORCE_INCREMENT : comme WRITE avec, en plus, la mise à jour de la version, même si l’entité n’a pas été modifiée

R. Grin JPA page 155

PESSIMISTIC_WRITE

L’entité est bloquée (pour les autres transaction) dès sa modification par la transaction qui a lancé le lock ; correspond à un select for update dans la base de donnéesEmpêche les autres transactions de bloquer en mode PESSIMISTIC_READ ou _WRITE(jusqu’à la fin de la transaction)Les autres transactions devront attendre la fin de la transaction pour pouvoir à leur tour modifier l’entité

R. Grin JPA page 156

Page 27: Plan de la partie 2 (1) JPA 2 - unice.frdeptinfo.unice.fr/.../minfo/modpersobj/supports/jpa2-2-6.pdf1 JPA 2.0 (Java Persistence API) - Partie 2Partie 2 Université de Nice - Sophia

27

PESSIMISTIC_READ

Mode utilisé par certaines bases de données pour empêcher les lectures non répétables, sans bloquer par un select for updateLes autres transactions ne peuvent modifier

é à ’ éles données qui correspondent à l’entité mais peuvent les lireEmpêche les autres transactions de bloquer en mode PESSIMISTIC_WRITE

R. Grin JPA page 157

Changement automatique de mode

Lorsqu’une transaction a bloqué une entité en mode PESSIMISTIC_READ et qu’elle modifie l’entité, le mode passe automatiquement en PESSIMISTIC_WRITE

R. Grin JPA page 158

Exception

Lorsque le fournisseur de persistance ne peut obtenir un blocage pessimiste et que le SGBD sous-jacent ne fait qu’un rollback de la requête (et pas de la transaction toute entière) une L kTi tE ti doitentière), une LockTimeoutException doit être lancée et la transaction ne doit être marquée pour un rollback

R. Grin JPA page 159

Autres méthodes pour le blocage

Il est possible d’indiquer un mode de blocage pour les entités ramenées par un find ou un queryrefresh permet aussi d’indiquer un blocage pour l’entité dont on rafraîchit l’état

R. Grin JPA page 160

Entité détachée

R. Grin JPA page 161

Les entités détachées sont surtout utiles dans les applications multi-tiers (avec Java EE et un serveur d’applications)Cette section survole les possibilités offertes

R. Grin JPA page 162

par les entités détachées

Page 28: Plan de la partie 2 (1) JPA 2 - unice.frdeptinfo.unice.fr/.../minfo/modpersobj/supports/jpa2-2-6.pdf1 JPA 2.0 (Java Persistence API) - Partie 2Partie 2 Université de Nice - Sophia

28

Cas d’utilisation des entités détachées

Une application multi-tiersLe serveur d’application récupère des données dans la BDCes données sont passées à la couche client

R. Grin JPA page 163

Ces données sont passées à la couche client, montrées à l’utilisateur qui peut les modifierLes modifications sont repassées au serveur et enregistrées dans la BDLes entités détachées facilitent l’implémentation d’un tel cas d’utilisation

Utilisation des entités détachées

Une fois détachées les entités peuvent être passées à la couche clienteLa couche cliente peut modifier les entités détachées

R. Grin JPA page 164

Ces entités peuvent ensuite être rattachées à un GE et les modifications effectuées dans la couche cliente peuvent être alors enregistrées dans la base de données lors d'un flush

Rattachement

La méthode merge de EntityManagerpermet d’obtenir une entité gérée à partir d’une entité détachéeSa signature :

R. Grin JPA page 165

<T> T merge(T entité)

Attention, l’entité passée en paramètre n’est pas rattachée ; c’est l’entité renvoyée par la méthode merge qui est rattachée ; cette entité a le même état et la même clé primaire que l’entité passée en paramètre

Si l’entité passée en paramètre de merge est déjà gérée par le GE, elle est renvoyée par la méthode merge

R. Grin JPA page 166

État d’une entité détachée

L’état d’une entité détachée peut ne pas être entièrement disponible

R. Grin JPA page 167

État d’une entité

Pour des raisons de performances, l'état d’une entité gérée par un GE peut ne avoir été complètement récupéré dans la BD (récupération retardé ; lazy)Le reste de l’état ne sera récupéré avec l’aide

R. Grin JPA page 168

Le reste de l état ne sera récupéré, avec l aide du GE, que lorsque l’entité en aura vraiment besoinSi l’entité est détachée alors qu’une partie de son état n’a pas encore été récupérée, la partie manquante de l’entité détachée ne sera pas disponible

Page 29: Plan de la partie 2 (1) JPA 2 - unice.frdeptinfo.unice.fr/.../minfo/modpersobj/supports/jpa2-2-6.pdf1 JPA 2.0 (Java Persistence API) - Partie 2Partie 2 Université de Nice - Sophia

29

Attribut disponible

Un attribut persistant d’une entité est immédiatement disponible dans les 2 cas suivants :n l’attribut a déjà été utilisé

R. Grin JPA page 169

n l’attribut n’a pas été marqué par fetch=LAZY(par défaut, les valeurs des attributs sont chargées en mémoire)

Association d’une entité détachée

Si une association d’un objet détaché a le mode de récupération LAZY, il est possible que l’association ne puisse être récupérée (dépend des circonstances et des fournisseurs d JPA)

R. Grin JPA page 170

de JPA)

Association « lazy » disponible

Si une association d’un objet détaché a le mode de récupération LAZY, il est possible de naviguer à travers cette association si

l’application a déjà effectué cette

R. Grin JPA page 171

n l’application a déjà effectué cette navigation

n ou si l’association a été chargée par un join fetch lors d’une requête

Rendre accessible l’état d’une entité détachée

2 solutions pour accéder à tout l’état (valeurs dans la base de données) d’une entité détachée

R. Grin JPA page 172

L’application récupère tout l’état de l’entité gérée avant le détachementL’application rattache l’entité par la méthode merge pour récupérer l’état manquant

Récupérer une association avant le détachement

Si le but est une entité (OneToOne ou ManyToOne), il suffit de lire une des propriétés de l’entité

R. Grin JPA page 173

Si le but est une collection (OneToMany ou ManyToMany), l’appel de la méthode size()de la collection suffit le plus souvent

Entité détachée et concurrence

Avant que les modifications sur l’entité détachée ne soient enregistrées dans la BD, l’entité doit être rattachée à un contexte de persistance (celui d’origine ou un autre)

R. Grin JPA page 174

A ce moment, ou au moment du commit qui enregistre vraiment les modifications, le contexte de persistance vérifie qu’il n’y a pas de conflit de concurrence

Page 30: Plan de la partie 2 (1) JPA 2 - unice.frdeptinfo.unice.fr/.../minfo/modpersobj/supports/jpa2-2-6.pdf1 JPA 2.0 (Java Persistence API) - Partie 2Partie 2 Université de Nice - Sophia

30

Conflit de concurrence

Si les données de la BD associée à un objet détaché ont été modifiées depuis le détachement de l’objet, merge lance une exception

R. Grin JPA page 175

Tout se passe donc comme si un conflit de concurrence avait été détecté (avec une stratégie optimiste)

Détachement automatique

Dans Java SE, quelques situations provoquent un détachement automatique des entités gérées :n Après un rollback

A è l d GE

R. Grin JPA page 176

n Après un clear du GEn Après la fermeture du GEnUn nouvel objet créé à partir à partir d’une

entité sérialisée est détaché (situation fréquente pour les applications distribuées)

Configuration d’une unité de persistance

R. Grin JPA page 177

d une unité de persistance

Fichier persistence.xml

Les informations doivent être données dans un fichier persistence.xmlDans un environnement non géré, ce fichier doit se situer dans le répertoire META-INF d’un des é t i d l th

R. Grin JPA page 178

répertoires du classpathDans un serveur d’applications, le répertoire META-INF peut se trouver à divers endroits : dans WEB-INF/classes, un fichier jar de WEB-INF/lib, un fichier jar de la racine d’un fichier EAR,… (voir spécification pour la liste complète)

Configuration d’une unité de persistance

Dans un environnent non géré par un serveur d’applications, il est nécessaire de donner les informations pour la connexion à la base de données

R. Grin JPA page 179

donnéesSouvent une application n’utilise qu’un seul compte utilisateur dans la base de données ; en ce cas, le nom et le mot de passe de ce compte sont donnés dans le fichier persistence.xml

Configuration d’une unité de persistance

Le fichier persistence.xml donne d’autres informations, comme n les noms des classes « gérées » dont les attributs

seront enregistrés dans la base (entités, classes

R. Grin JPA page 180

g ( ,Embeddable, classes « mapped superclasses »)

n la configuration de l’environnement de mis au point (logging, affichage des ordres SQL lancés dans le SGBD,…)

n des propriétés particulières au driver du fournisseur de persistance

Page 31: Plan de la partie 2 (1) JPA 2 - unice.frdeptinfo.unice.fr/.../minfo/modpersobj/supports/jpa2-2-6.pdf1 JPA 2.0 (Java Persistence API) - Partie 2Partie 2 Université de Nice - Sophia

31

persistence.xml<persistencexmlns="http://java.sun.com/xml/ns/persistence"version= "1.0" ><persistence-unit name="Employes"

transaction-type="RESOURCE_LOCAL"><class>p1.Employe</class> noms des

R. Grin JPA page 181

p p y /<class>p1.Dept</class><properties>

. . . <!– Voir transparent suivant--></properties>

</persistence-unit></persistence>

noms desclasses gérées

Section properties

La section properties dépend du fournisseur des fonctionnalités décrites dans la spécification JPAElle contient les informations pour la

R. Grin JPA page 182

connexion mais aussi d’autres informations pour le logging ou la création automatique des tables si elle n’existent pas déjà ; il faut consulter la documentation du fournisseur

Exemple de section properties

<properties><property

name="eclipselink.jdbc.driver"value="oracle.jdbc.OracleDriver"/>

<propertyli li k jdb l

R. Grin JPA page 183

name="eclipselink.jdbc.url"value="jdbc:oracle:thin:@...:INFO "/>

<property name="eclipselink.jdbc.user" value="toto"/>

<property name="eclipselink.jdbc.password" value="mdp"/>

</properties>

Source de données

Lorsque JPA est utilisé avec un serveur d’applications, une source de données fournie par le serveur d’applications est le plus souvent utilisée pour obtenir les connexions (voir D t S dans le cours sur JDBC)

R. Grin JPA page 184

(voir DataSource dans le cours sur JDBC)On pourra alors trouver :<persistence-unit name="Employe"><jta-data-source>jdbc/EmployeDS</jta-

data-source></persistence-unit name=Employe>

Configuration dynamique (1)

Les informations pour la connexion à la base, en particulier le nom et le mot de passe de connexion à la base, peuvent n’être connues qu’à l’exécution et pas au moment de l’é it d dl’écriture du codeEn ce cas, il est possible de ne donner les informations que lors de la création de la fabrique par la classe Persistence

R. Grin JPA page 185

Configuration dynamique (2)

Il suffit de passer à la méthode createEntityManagerFactory une mapqui contient les propriétés qui écrasent les valeurs contenues dans persistence.xml

R. Grin JPA page 186

Page 32: Plan de la partie 2 (1) JPA 2 - unice.frdeptinfo.unice.fr/.../minfo/modpersobj/supports/jpa2-2-6.pdf1 JPA 2.0 (Java Persistence API) - Partie 2Partie 2 Université de Nice - Sophia

32

Exemple de configuration dynamique

// Saisie du nom et du mot de passe. . .// Configuration de la connexionMap props = new HashMap();

t(" li li k jdb " )props.put("eclipselink.jdbc.user", nom);props.put("eclipselink.jdbc.password", mdp);EntityManagerFactory emf = Persistence.createEntityManagerFactory(

"employes", props);

R. Grin JPA page 187

Les ajouts de EclipseLink

EclipseLink a des extensions par rapport à la norme JPAPar exemple,n logging

R. Grin JPA page 188

gg gn génération automatique de tablesn…

Génération automatique des tablesLa propriété eclipselink.ddl-generationpermet de créer automatiquement les tables au moment de la création de la fabrique de gestionnaires d’entitésCette propriété peut avoir 3 valeurs :

R. Grin JPA page 189

n none : aucune création automatiquen create-tables : les tables sont créées si

elles n’existent pas déjàn drop-and-create-tables : si une table

existe déjà, elle est d’abord supprimée avant d’être recréée (utile pour les tests)

Exemple

<properties>. . .<propertyname="eclipselink.ddl-generation"

l "d d t t bl "/>

R. Grin JPA page 190

value="drop-and-create-tables"/></properties>

eclipselink.ddl-generation.output-modeindique ce qui sera fait avec les fichiers DDLValeurs possibles : n sql-script génère les fichiers mais ne

R. Grin JPA page 191

les exécute pasn database exécute les ordres DDL mais

ne génère pas les fichiersn both génère les fichiers et les exécute

(valeur par défaut)

eclipselink.application-locationindique le nom du répertoire qui contiendra les fichiers contenant les ordres DDL de création et de suppression des tables (le é t i t déf t)

R. Grin JPA page 192

répertoire courant par défaut)

Page 33: Plan de la partie 2 (1) JPA 2 - unice.frdeptinfo.unice.fr/.../minfo/modpersobj/supports/jpa2-2-6.pdf1 JPA 2.0 (Java Persistence API) - Partie 2Partie 2 Université de Nice - Sophia

33

eclipselink.create-ddl-jdbc-file-nameindique le nom du fichier qui contiendra les ordres de création des tables ; par défaut, createDDL.jdbc

R. Grin JPA page 193

eclipselink.drop-ddl-jdbc-file-nameidem pour la suppression des tables ; par défaut, dropDDL.jdbc

logging (1)

La propriété eclipselink.logging.levelpeut avoir les valeursn OFF : aucune information

n SEVERE : uniquement les erreurs

R. Grin JPA page 194

n WARNING : les avertissements (et les erreurs)

n INFO (valeur par défaut) : assez peu d’information en plus

n CONFIG : donne des informations au moment du déploiement sur la configuration

logging (2)

n FINE : donne des informations sur les ordres SQL utile pendant les tests et la mise au point

n FINER : encore plus d’informations, par exemple sur les transactionsFINEST l d’i f ti

R. Grin JPA page 195

n FINEST : encore plus d’informations, par exemple sur l’utilisation des séquences

Fichiers XML

R. Grin JPA page 196

Placement des fichiers XML

Par défaut les fichiers XML contenant les méta données sont placées dans le fichier META-INF/orm.xml, sous un répertoire du classpath

R. Grin JPA page 197

Il est possible d’indiquer d’autres emplacements avec le tag <mapping-file>dans le fichier persistence.xml qui définit l’unité de persistance

Exemple

<persistence-unit name="xxxx">...<mapping-file>META-INF/queries.xml</mapping-file>< i fil >META INF/ titi l

R. Grin JPA page 198

<mapping-file>META-INF/entities.xml</mapping-file>

</persistence-unit>

Page 34: Plan de la partie 2 (1) JPA 2 - unice.frdeptinfo.unice.fr/.../minfo/modpersobj/supports/jpa2-2-6.pdf1 JPA 2.0 (Java Persistence API) - Partie 2Partie 2 Université de Nice - Sophia

34

Méta-données par défautL’élément <persistence-unit-defaults>contient des valeurs par défaut qui s’appliquent à toutes les entités de l’unité de persistanceLes sous-éléments peuvent être : <schema>(donner le nom du schéma relationnel),

R. Grin JPA page 199

(donner le nom du schéma relationnel), <catalog> (idem <schema> pour les SGBD qui supportent les catalogues), <access>(accès pour toutes les classes non annotées), <cascade-persist> (pour imposer la persistance par transitivité) et <entity-listeners> (écouteurs par défaut)

Fichiers XML – annotationsAvantages des annotations :nméta données proches du coden pas besoin de donner le contexte comme

dans les fichiers XMLn plus simple

R. Grin JPA page 200

n plus simpleInconvénients :n changement des méta données nécessite

une recompilationLes informations données dans les fichiers XML l’emportent sur les annotations

Fichiers XML – annotations

Les annotations sont le plus souvent utiliséesLes fichiers de configuration XML peuvent être préférés lorsque l’information n est dépendante de l’environnement

d’ é i l l d

R. Grin JPA page 201

d’exécution ; par exemple pour les noms de tables ou de colonnes

n concerne plusieurs classes ; par exemple @TableGenerator qui donne le nom de la table qui génère automatiquement les clés d’identification des entités

Exemple de fichier orm.xml (en-tête)

<?xml version="1.0" encoding="UTF-8" ?><entity-mappings xmlns="http://java.sun.com/xml/ns/persistence.orm"xmlns:xsi:"http://www w3 org/2001/XMLSchema

R. Grin JPA page 202

xmlns:xsi: http://www.w3.org/2001/XMLSchema-instance"xsi-schemaLocation ="http://java.sun.com/xml/ns/persistence.xml http://java.sun.com/xml/ns/persistence/orm_1_0.xsd" version="1.0">

Exemple de fichier orm.xml (fin)

<entity class="jpa.Employe"><table name="EMP" /><named-query name="findEmpByName"

<query>select e from Employe e where e nom like :nomEmploye</query>

R. Grin JPA page 203

e.nom like :nomEmploye</query></named-query>

</entity></entity-mappings>

JPA et DAO

R. Grin JPA page 204

Page 35: Plan de la partie 2 (1) JPA 2 - unice.frdeptinfo.unice.fr/.../minfo/modpersobj/supports/jpa2-2-6.pdf1 JPA 2.0 (Java Persistence API) - Partie 2Partie 2 Université de Nice - Sophia

35

Utilité des DAO ?

La possibilité de détacher et rattacher une entité rend souvent les DTO inutiles (voir cours sur DAO et modèles de conception associés)

R. Grin JPA page 205

Puisque JPA augmente fortement la portabilité du code chargé de la persistance, est-ce que les DAOs sont encore nécessaires ?

Les DAOs ne sont pas toujours utiles

Pour les petites applications à existence courte, avec peu de fonctionnalités « métier », l’utilisation directe de JPA depuis le code métier (sans utilisation de DAOs) simplifie le code lié à la persistance

R. Grin JPA page 206

code lié à la persistanceLes DAO ne sont alors pas vraiment utiles car JPA offre malgré tout une meilleure portabilité que JDBC et l’utilisation des DAOs rend le code un peu plus complexe

Les DAOs sont encore utiles

Pour les applications plus complexes, les DAOs peuvent apporter une meilleure abstraction et une meilleure factorisation du code lié à la persistanceLes détails techniques liés à JPA (ou à une

R. Grin JPA page 207

Les détails techniques liés à JPA (ou à une version de JPA) peuvent être cachés dans la couche DAOLes DAOs pourront aussi faciliter le passage éventuel à un autre type de persistance, par exemple à un SGBD objet

Exemple de factorisation du code

Un DAO peut contenir des méthodes spécialement adaptées au « métier »Par exemple, une méthode qui renvoie la liste des candidats qui ont obtenu leur examen

R. Grin JPA page 208

avec une certaine mention, passée en paramètreCette méthode peut être appelée de plusieurs endroits du code « métier »

Variantes des DAOs

Parmi toutes les variantes des méthodes des DAOs (voir cours sur les DAOs), celles qui prennent en paramètre ou qui renvoient des objets (des entités JPA dans ce cas) sont le

l t h i i

R. Grin JPA page 209

plus souvent choisiesEn effet, les entités détachées peuvent jouer le rôle des DTOs qui sont donc inutiles, et les variantes qui utilisent plusieurs paramètres dont les valeurs correspondent aux propriétés des objets compliquent inutilement le code

DAOs génériques

La généricité permet d’écrire une classe mère générique de tous les DAOs, ce qui allège d’autant les classes filles représentant chacune des classes DAOs

R. Grin JPA page 210

Le type des entités gérées et le type de l’identificateur sont les paramètres de type de ce DAO génériqueLes transparents suivants sont un exemple d’implémentation que vous pouvez modifier à votre convenance

Page 36: Plan de la partie 2 (1) JPA 2 - unice.frdeptinfo.unice.fr/.../minfo/modpersobj/supports/jpa2-2-6.pdf1 JPA 2.0 (Java Persistence API) - Partie 2Partie 2 Université de Nice - Sophia

36

Interface DAO générique

public interface DaoGenerique<T,ID extends Serializable> {T findById(ID id);List<T> findAll();void create(T objet);

R. Grin JPA page 211

void create(T objet);void delete(T entite);T update(T entite);

}

Interface DAO pour une entité

public interface StyloDao extends DaoGenerique<Stylo, Long> { }

On peut ajouter des méthodes adaptée au « métier », comme cette méthode qui renvoie toutes les marques de stylos en vente :

R. Grin JPA page 212

toutes les marques de stylos en vente :public interface StyloDao extends DaoGenerique<Stylo, Long> {List<String> findMarques();

}

Classe DAO générique (1)public abstract class DaoGeneriqueJpa<T, ID extends Serializable> implements DaoGenerique<T, ID> {private Class<T> classeEntite;private EntityManager em;bli G i () {

R. Grin JPA page 213

public DaoGeneriqueJpa() {// classe concrète de T passée à findthis.classeEntite = (Class<T>)

((ParameterizedType)getClass()..getGenericSuperclass()).getActualTypeArguments()[0];

}

Classe DAO générique (2)public void insert(T objet) {

em.persist(objet);}public void delete(T objet) {

em.remove(objet);}

R. Grin JPA page 214

}public T findById(ID id) {

return em.find(classeEntite, id);}public T update(T entite) {

return em.merge(entite);}

Classe DAO générique (3)

public void setEntityManager(EntityManager em) {

this.em = em;}protected EntityManager

R. Grin JPA page 215

getEntityManager() {return this.em;

}}

DAO pour une entité

public class StyloDaoJpaextends DaoGeneriqueJpa<Stylo, Long> implements StyloDao {

public List<Stylo> findAll() {Query query = getEntityManager()

R. Grin JPA page 216

Q y q y g y g ().createNamedQuery("Stylo.findAll");

return(List<Stylo>)query.getResultList();

}

}

Page 37: Plan de la partie 2 (1) JPA 2 - unice.frdeptinfo.unice.fr/.../minfo/modpersobj/supports/jpa2-2-6.pdf1 JPA 2.0 (Java Persistence API) - Partie 2Partie 2 Université de Nice - Sophia

37

Cache des données

R. Grin JPA page 217

UtilitéTous les fournisseurs de persistance utilisent un cache de second niveau (en plus du contexte de persistance) pour éviter des accès aux bases de données, et donc améliorer les performances

R. Grin JPA page 218

Tous les gestionnaires d’entités d’une même unité de persistance utilisent le même cache de second niveauSi une donnée est lue par un gestionnaire et gardée dans le cache, elle pourra être lue par les autres gestionnaires sans accès à la BD

Utilité

La spécification JPA 2 standardise en partie l’utilisation du cache de 2ème niveau ; il faut consulter la documentation du fournisseur de persistance pour connaître les autres

ibilité é t ll

R. Grin JPA page 219

possibilités éventuelles

Utilisation des caches

Il n’est pas toujours facile d’utiliser correctement le cache de 2ème niveauLe plus souvent on peut se contenter d’indiquer quelles classes utiliseront ce cache

R. Grin JPA page 220

Par exemple, il peut être très intéressant d’utiliser un cache pour des classes dont les données ne changent que très rarement comme les noms des pays

Problèmes éventuels

Parfois ce cache pose des problèmes si la base de données est utilisée en parallèle par d’autres applicationsPar exemple, si des entités liées à une entité

R. Grin JPA page 221

sont supprimées de la base en dehors de l’application, le cache peut penser modifier une ligne avec un UPDATE au lieu d’en insérer une nouvelle avec un INSERT, ce qui provoque une erreur

Solutions (1)

L’utilisation de la méthode refresh de EntityManager permet de récupérer dans la base de données des données « fraiches », sans jamais passer par le cache

R. Grin JPA page 222

Un blocage pessimiste peut parfois être la solution si on souhaite interdire la modification de lignes par une autre application (implémentation dépendante du fournisseur de persistance)

Page 38: Plan de la partie 2 (1) JPA 2 - unice.frdeptinfo.unice.fr/.../minfo/modpersobj/supports/jpa2-2-6.pdf1 JPA 2.0 (Java Persistence API) - Partie 2Partie 2 Université de Nice - Sophia

38

Solutions (2)

Parfois la seule solution est de vider le cache ou d’indiquer au fournisseur de ne pas utiliser le cache pour effectuer certaines opérations (la façon de faire dépend en partie du f i d i t )

R. Grin JPA page 223

fournisseur de persistance)JPA 2 permet d’effectuer certains réglages pour optimiser l’utilisation du cache, et éviter les problèmes liés aux données qui ne sont pas à jour dans le cache

Utilisation ou non du cacheLe fichier persistence.xml peut indiquer si une unité de persistance utilisera ou non un cache avec l’élément caching qui peut avoir 4 valeurs possibles : ALL, NONE, ENABLE DELECTIVE et _DISABLE_SELECTIVE

Exemple :<caching>ENABLE_SELECTIVE</caching>

Pas de valeur par défaut ; il faut donc toujours donner une valeur pour avoir une application portable entre les fournisseurs de persistance

R. Grin JPA page 224

Utilisation ou non du cache

ALL : un cache sera utilisé pour toutes les entitésNONE : aucun cache ne sera utiliséENABLE_SELECTIVE : par défaut, les entités _ne sont pas cachées ; seules le sont celles qui sont annotées par @Cacheable(true)DISABLE_SELECTIVE : par défaut, les entités sont cachées ; seules ne le sont pas celles qui sont annotées par @Cacheable(false)

R. Grin JPA page 225

Annotation @Cacheable

Une classe d’entités peut être annotée pour indiquer si les entités de la classe seront conservées dans le cache (voir élément caching de persistence.xml pour plus d é i i )de précisions)Exemple :@Entity@Cacheable(true)public class Pays { ... }

R. Grin JPA page 226

@Cacheable suffit cartrue est la valeur par défaut

Interface CacheJPA 2 a introduit cette interface simplifiée avec le cache pour affiner les indications données par @CacheablePar exemple, pour une classe d’entités « cacheable », il est possible d’enlever une certaine entité du cacheSi le cache n’est pas utilisé, les méthodes ne font rien, à part contains qui renvoie toujours falseLe cache s’obtient avec la méthode getCache() de EntityManagerFactory

R. Grin JPA page 227

Méthodes de l’interface Cache

boolean contains(Class cls, Object cléPrimaire) indique si le cache contient une entitévoid evict(Class cls) enlève du cache t t l tité d’ t i ltoutes les entités d’une certaine classevoid evict(Class cls, Object cléPrimaire) enlève du cache une certaine entitévoid evictAll() vide le cache

R. Grin JPA page 228

Page 39: Plan de la partie 2 (1) JPA 2 - unice.frdeptinfo.unice.fr/.../minfo/modpersobj/supports/jpa2-2-6.pdf1 JPA 2.0 (Java Persistence API) - Partie 2Partie 2 Université de Nice - Sophia

39

Propriétés liées au cache

En plus de toutes les possibilités déjà exposées, on peut donner des indications pour les méthodes find, refresh et pour les requêtes (Query) exécutées par un

ti i d’ tité ( i é ifi tigestionnaire d’entités (voir spécification pour plus de détails)Exemple :em.setProperty(QueryHints.CACHE_RETRIEVE_MODE, CacheRetrieveMode.USE);

R. Grin JPA page 229

Propriétés pour un find

Il est possible de donner des indications d’utilisation du cache pour un seul findExemple :HashMap props = new HashMap();

t(Q Hi t CACHE RETRIEVE MODEprops.put(QueryHints.CACHE_RETRIEVE_MODE, CacheRetrieveMode.BYPASS);

em.find(MyEntity.class, id, props);

R. Grin JPA page 230

Propriétés pour les commit

Il est aussi possible d’indiquer si les données validées par un commit seront mises dans le cache

R. Grin JPA page 231

Optimisations

R. Grin JPA page 232

Les performances d’une application peuvent être grandement améliorées parn un choix adapté du mode de récupération

des entités associées

R. Grin JPA page 233

n l’utilisation d’opérations de modifications en volume, sans création d’entités

n une bonne utilisation du cache de 2ème

niveau

Méthode callback et listener

R. Grin JPA page 234

Page 40: Plan de la partie 2 (1) JPA 2 - unice.frdeptinfo.unice.fr/.../minfo/modpersobj/supports/jpa2-2-6.pdf1 JPA 2.0 (Java Persistence API) - Partie 2Partie 2 Université de Nice - Sophia

40

Méthodes « callback » Des méthodes peuvent être annotées pour indiquer qu’elles seront appelées par le fournisseur de persistance quand une entité passera dans une nouvelle étape de son cycle de vie

R. Grin JPA page 235

Ces méthodes peuvent appartenir à une classe entité (entity) ou classe mère « mappedSuperclass » ou à une classe « écouteur » (listener)Une méthode peut être annotée par plusieurs de ces annotations

Annotations@PrePersist : quand persist (ou merge) s’est terminé avec succès@PostPersist : après l’insertion dans la BD@PreRemove : quand remove est appelé

R. Grin JPA page 236

@PostRemove : après suppression dans la BD@PreUpdate : avant modification dans la BD@PostUpdate : après modification dans la BD@PostLoad : après la lecture des données de la BD pour construire une entité

Callback dans fichier XML

Les méthodes callback peuvent aussi être indiquées dans un fichier XMLUn fichier XML peut aussi indiquer des listeners par défaut qui seront appelées pour

R. Grin JPA page 237

toutes les entités, dans le sous-élément <entity-listeners> de l’élément <persistence-unit-defaults>

Exemples d’utilisation

Un trigger de la base de données peut donner les valeurs de l’utilisateur qui a modifié pour la dernière fois une entité, avec la date de cette modification

R. Grin JPA page 238

Pour remplacer un tel trigger, il est possible d’ajouter une méthode annotée par @PrePersist qui remplit ces valeurs dans les entitésUne méthode callback peut aussi initialiser des attributs non persistants d’une entité

Callback dans une entité

Ces méthodes ne doivent aucune paramètre et le type retour doit être voidElles ne doivent pas avoir de clause throwsSi elles renvoient une exception non

ôlé l é ll é h d

R. Grin JPA page 239

contrôlée, les éventuelles méthodes callbacks suivantes ne sont pas appelées et la transaction est marquée pour un rollback(elle ne pourra pas être validée) Une seule méthode callback d’un certain type (par exemple PrePersist) par entité

Callback dans un écouteur

La signature doit avoir un paramètre compatible avec le type de l’entité gérée pour qu’il puisse contenir l’instance de l’entité« Compatible » signifie que le type doit être un

R. Grin JPA page 240

« surtype » de la classe entité : la classe de l’entité, ou une classe mère, ou une interface implémentée par la classe de l’entitéUne classe listener ne doit contenir aucune variable d’instance (elle doit être « sans état ») et doit avoir un constructeur sans paramètre

Page 41: Plan de la partie 2 (1) JPA 2 - unice.frdeptinfo.unice.fr/.../minfo/modpersobj/supports/jpa2-2-6.pdf1 JPA 2.0 (Java Persistence API) - Partie 2Partie 2 Université de Nice - Sophia

41

Attacher un écouteur

L’annotation @EntityListeners permet d’attacher un ou plusieurs écouteurs à une classe entitéExemple :

R. Grin JPA page 241

@Entity@EntityListeners({C1.class, C2.class})public class Entite {

Ordre d’appel

Lorsque un événement du cycle de vie survient, les différentes méthodes sont appelées dans cet ordre :

1. Méthodes des listeners par défaut

R. Grin JPA page 242

2. Méthodes des listeners3. Méthode de l’entité en cause

Validation des données

R. Grin JPA page 243

Généralités

JPA 2 permet de valider les données automatiquement durant le cycle de vie d’une entité, dans les phases « pre-persist », « pre-update » et « pre-remove », ce qui permet d’é i l’é it d’ é t d t ld’économiser l’écriture d’un écouteur dont le rôle ne serait que de valider des entitésCette validation s’appuie sur l’API de validation (JSR 303) qui peut être utilisée par tout code Java (Java SE ou Java EE) ; cette API ne sera pas détaillée dans ce cours

R. Grin JPA page 244

Configuration

Par défaut, les entités sont validées dans les phases pre-persist et pre-update pour le groupe de validation Default (voir API de validation) ; aucune contrainte n’est validée

l hpour la phase pre-removeIl est possible de configurer le mode de validation (validation ou non) par l’élément <validation-mode> du fichier persistence.xml ou par une propriété passée à la méthode createEntityManagerFactory

R. Grin JPA page 245

Exemple d’entité

@Entitypublic class Client {@Id @NotNullprivate int id;@N tN ll @Si ( 60)@NotNull @Size(max=60)private String nom;@(groups=Remove.class,min=0,max=0)private int nbLivraisonsEnCours;...

}

R. Grin JPA page 246

Page 42: Plan de la partie 2 (1) JPA 2 - unice.frdeptinfo.unice.fr/.../minfo/modpersobj/supports/jpa2-2-6.pdf1 JPA 2.0 (Java Persistence API) - Partie 2Partie 2 Université de Nice - Sophia

42

Validations standard (1/3)

@Null, @NotNullPour toutes les contraintes suivantes, null est considéré comme valide@AssertTrue, @AssertFalse : valeur booléenne imposée (boolean ou Boolean)@Min, @Max : bornes pour un entier (long) ; tous les types de nombres sont supportés, sauf double et float (à cause des erreurs d’arrondi)@DecimalMin, @DecimalMax : bornes pour une valeur décimale (String)

R. Grin JPA page 247

Validations standard (2/3)

@Size avec les attributs min et max ; types supportés : String, Collection, Map, tableau@Digits avec les attributs integer et

fffraction : nombres maximums de chiffres dans les parties entières et décimales ; types supportés : BigDecimal, String, tous les types entiers (int, Integer, byte,...), y compris BigInteger, mais pas les types double et float (erreurs d’arrondi)

R. Grin JPA page 248

Validations standard (3/3)

@Past, @Future : date avant ou après la date actuelle ; types supportés : Date et Calendar du paquetage java.util@Pattern : la valeur correspond à une

é è ’expression régulière ; l’attribut flags peut comporter des valeurs utiles pour vérifier la concordance (voir javadoc de java.util.regex.Pattern) : UNIX_LINES, CASE_INSENSITIVE, MULTILINE,...

R. Grin JPA page 249

Validations particulières

Il est possible d’ajouter des validations aux validations standard ; pas étudié dans ce cours

R. Grin JPA page 250

Précisions sur le schéma de la base de données

R. Grin JPA page 251

de la base de données

Génération du schéma

Tous les fournisseurs de persistance fournissent des propriétés pour indiquer que le schéma de la base de données sera généré automatiquement à partir des l J

R. Grin JPA page 252

classes JavaEn ce cas, il est possible de donner des précisions sur le schéma généré

Page 43: Plan de la partie 2 (1) JPA 2 - unice.frdeptinfo.unice.fr/.../minfo/modpersobj/supports/jpa2-2-6.pdf1 JPA 2.0 (Java Persistence API) - Partie 2Partie 2 Université de Nice - Sophia

43

Contrainte d’unicité sur une colonne

@Column(unique=true)

Une contrainte d’unicité sera ajoutée dans la définition de la colonne de la tableComme dans toute cette section, l’attribut unique ne servira à rien (sinon pour la documentation du code) si le schéma n’est pas généré automatiquement

R. Grin JPA page 253

Contrainte d’unicité sur une table

@Table(uniqueConstraints =@UniqueConstraint(columnNames = {"COL1", "COL2"}))

Une contrainte d’unicité sera ajoutée dans la définition de la table

R. Grin JPA page 254

Contraint NULL

@Column(nullable=false)Une contrainte NOT NULL sera ajoutée à la définition de la colonne

R. Grin JPA page 255

Types de données

@Column(length=25)précise la taille de la colonne de type chaîne de caractères (longueur 255 par défaut)@Column(precision=10, scale=2)précise la précision (le nombre total de chiffres) et le nombre de chiffres après la virgule pour une colonne de type nombre décimal (float, double,…)

R. Grin JPA page 256

Définition quelconque

On peut même donner la définition du type d’une colonne pour prendre en compte des particularités de certains SGBDL’attribut columnDefinition des annotations @Col mn @JoinCol mnannotations @Column, @JoinColumn, @PrimaryKeyJoinColumn, @DiscriminatorColumn permet de définir un type particulierExemple : @Column(columnDefinition="NVARCHAR2(8)")

R. Grin JPA page 257

Bibliographie

R. Grin JPA page 258

Page 44: Plan de la partie 2 (1) JPA 2 - unice.frdeptinfo.unice.fr/.../minfo/modpersobj/supports/jpa2-2-6.pdf1 JPA 2.0 (Java Persistence API) - Partie 2Partie 2 Université de Nice - Sophia

44

Sites Web

Spécification officielle de JPA 2 :http://jcp.org/en/jsr/detail?id=317Eclipselink :http://www.eclipse.org/eclipselink/jpa.php

R. Grin JPA page 259

Hibernate : http://www.hibernate.org/hib_docs/entitymanager/reference/en/html/Open JPA :http://openjpa.apache.org/

Livres

Pro JPA 2: Mastering the Java™ Persistence APIde Mike Keith et Merrick SchincariolEdition Apress

R. Grin JPA page 260

Java Persistence with Hibernatede Christian Bauer et Gavin KingEdition Manning(en anglais ; pour la version 1 de JPA)