Académique Documents
Professionnel Documents
Culture Documents
Présentation de JPA
JPA Entités persistantes
1
JPA Avertissement
JPA va sans doute devenir un standard pour la JPA est le plus souvent utilisé dans le
persistance des objets Java contexte d’un serveur d’application
Pour plus de précisions, lire la spécification à Ce cours étudie l’utilisation de JPA par une
l’adresse application autonome, en dehors de tout
http://jcp.org/aboutJava/communityprocess/pfd/js serveur d’application
r220/index.html Des informations sur l’utilisation de JPA avec
un serveur d’applications sont données à la
fin de ce support
2
Exemple d’entité – l’identificateur Exemple d’entité – une propriété
@Id
@GeneratedValue public String getNom() {
public int getId() { return nom;
return id; }
} public void setNom(String nom) {
public void setId(int id) { this.nom = nom;
this.id = id; }
}
3
Exemple Exemple (suite)
String queryString =
EntityManagerFactory emf = Persistence.
"SELECT e FROM Employe e "
createEntityManagerFactory("employes"); + " WHERE e.poste = :poste";
EntityManager em = Query query = em.createQuery(queryString);
emf.createEntityManager(); query.setParameter("poste", "INGENIEUR");
EntityTransaction tx = em.getTransaction(); List<Employe> liste =
tx.begin(); query.getResultList();
Dept dept = new Dept("Direction", "Nice"); for (Employe e : liste) {
em.persist(dept); System.out.println(e.getNom());
sera enregistré dans
dept.setLieu("Paris"); la base de données }
em.close();
tx.commit();
…au moment du emf.close()
R. Grin commit
JPA page 19 R. Grin JPA page 20
Caractéristiques
Seules les entités peuvent être
n renvoyées par une requête (Query)
Conditions pour les classes entités Conditions pour les classes entités
Une classe entité doit avoir un constructeur Une classe entité ne doit pas être une classe
sans paramètre protected ou public interne
Elle ne doit pas être final Une entité peut être une classe abstraite mais
Aucune méthode ou champ persistant ne doit elle ne peut être une interface
être final
Si une instance peut être passée par valeur en
paramètre d’une méthode comme un objet
détaché, elle doit implémenter Serializable
Elle doit posséder un attribut qui représente la
clé primaire dans la BD
R. Grin JPA page 23 R. Grin JPA page 24
4
Convention de nommage JavaBean 2 types d’accès
Un JavaBean possède des propriétés Le fournisseur de persistance accédera à la
Une propriété est représentée par 2 valeur d’une variable d’instance
accesseurs (« getter » et « setter ») qui n soit en accédant directement à la variable
5
Cycle de vie d’une instance d’entité Cycle de vie d’une instance d’entité
n détachée : elle a une identité dans la base
L’instance peut être mais elle n’est plus associée à un contexte
n nouvelle (new) : elle est créée mais pas de persistance (une entité peut devenir
associée à un contexte de persistance détachée à la fin d’une transaction ou par
n gérée par un gestionnaire de persistance ; un passage par valeur en paramètre d’une
elle a une identité dans la base de données méthode distante)
(un objet peut devenir géré par la méthode n supprimée : elle a une identité dans la
persist, ou merge d’une entité détachée, base ; elle est associée à un contexte de
ou si c’est une instance « récupérée » dans persistance et ce contexte doit la
la base par une requête) supprimer de la base de données (passe
dans cet état par la méthode remove)
R. Grin JPA page 31 R. Grin JPA page 32
6
Nom de colonne Classe Embeddable
Les entités persistantes ne sont pas les seules
Pour donner à une colonne de la table un autre classes persistantes
nom que le nom de l’attribut correspondant, il
Il existe aussi des classes « insérées » ou
faut ajouter une annotation @Column
« incorporées » (embedded) dont les données
Cette annotation peut aussi comporter des
n’ont pas d’identité dans la BD mais sont
attributs pour définir plus précisément la insérées dans une des tables associées à une
colonne entité persistante
Exemple :
Elles peuvent être annotées comme les entités
@Column(name="AUTRENOM",
updatable=false, length=80) (avec @Column par exemple)
public String getTruc() { ... } Par exemple, une classe Adresse dont les
valeurs sont insérées dans la table Employe
R. Grin JPA page 37 R. Grin JPA page 38
7
@AttributeOverride(s) Exemple
Un champ annoté par @Embedded peut être @Entity
complété par une annotation public class Employe {
@AttributeOverride, ou plusieurs de ces @Embedded
annotations insérées dans une annotation @AttributeOverrides({
@AttributeOverrides @AttributeOverride(
name="ville",
Ces annotations permettent d’indiquer le nom
column=@column(name="villeTravail")),
d’une ou de plusieurs colonnes dans la table
de l’entité @AttributeOverride(...)
})
Elles peuvent aussi être utilisées si une
// Adresse du travail
classe insérée est référencée par plusieurs
private Adresse adresseTravail;
classes entités différentes
R. Grin JPA page 43 R. Grin JPA page 44
8
Annotation pour les types temporels Exemple
3 types temporels dans l’énumération
@Temporal(TemporalType.DATE)
TemporalType : DATE, TIME, TIMESTAMP
private Calendar dateEmb;
Correspondent aux 3 types de SQL ou du
paquetage java.sql : Date, Time et
Timestamp
Exemple
@Entity
@Table(name="PARTICIPATION2",
uniqueConstraints =
@UniqueConstraint(
Gestionnaire d’entités
columnNames = (Entity Manager), GE
{"EMPLOYE_ID", "PROJET_ID"})
)
public class Participation {
...
}
9
Principe de base Unité de persistance
La persistance des entités n’est pas C’est une configuration nommée qui contient les
transparente informations nécessaires à l’utilisation d’une base
Une instance d’entité ne devient persistante de données
que lorsque l’application appelle la méthode Elle est associée à un ensemble de classes
appropriée du gestionnaire d’entité (persist entités
ou merge)
Cette conception a été voulue par les
concepteurs de l’API par souci de flexibilité et
pour permettre un contrôle fin de l’application
sur la persistance des entités
R. Grin JPA page 55 R. Grin JPA page 56
10
Interface EntityManager Types de GE
Elle représente un GE GE géré par le container (uniquement
disponible dans un serveur d’applications)
Implémentation fournie par le fournisseur de
n délimité par les transactions
persistance
(TRANSACTION)
n peut survivre à une fin de transaction
(EXTENDED) ; nécessite un bean session
avec état (stateful)
GE géré par l’application (seul type disponible
en dehors d’un serveur d’applications) ; pas
délimité par les transactions
R. Grin JPA page 61 R. Grin JPA page 62
11
Méthodes de EntityManager Méthodes de EntityManager
void lock(Object entité, Query createNativeQuery(String
LockModeType lockMode) requête)
void refresh(Object entité) Query createNativeQuery(String
void clear() requête, Class classeRésultat)
boolean contains(Object entité) void joinTransaction()
flush flush
Toutes les modifications effectuées sur les Un flush est automatiquement effectué au
entités du contexte de persistance gérées par moins à chaque commit de la transaction en
le GE sont enregistrées dans la BD lors d’un cours
flush du GE Une exception
Au moment du flush, le GE étudie ce qu’il doit TransactionRequiredException est
faire pour chacune des entités qu’il gère et il levée si la méthode flush est lancée en
lance les commandes SQL adaptées pour dehors d’une transaction
modifier la base de données (INSERT,
UPDATE ou DELETE)
12
persist persist(A)
Si A est nouvelle, elle devient gérée
Une entité « nouvelle » devient une entité
Si A était déjà gérée, persist est ignorée
gérée
mais l’opération persist « cascade » sur les
L’état de l’entité sera sauvegardé dans la BD
entités associées si l’association a l’attribut
au prochain flush ou commit CascadeType.PERSIST
Aucune instruction ne sera nécessaire pour
Si A est supprimée, elle devient gérée
faire enregistrer au moment du commit dans
la base de données les modifications Si A est détachée, une
IllegalArgumentException est lancée
effectuées sur l’entité par l’application ; en
effet le GE conserve toutes les informations Ne peut être utilisé que dans le contexte
nécessaires sur les entités qu’il gère d’une transaction
R. Grin JPA page 73 R. Grin JPA page 74
remove remove(A)
refresh refresh(A)
Le GE peut synchroniser avec la BD une Ignorée si A est nouvelle ou supprimée
entité qu’il gère en rafraichissant son état en
Si A est nouvelle, l’opération « cascade » sur
mémoire avec les données actuellement
les associations qui ont l’attribut
dans la BD :
CascadeType.REFRESH
em.refresh(entite);
Si A est détachée, une
Les données de la BD sont copiées dans
IllegalArgumentException est lancée
l’entité
Utiliser cette méthode pour s’assurer que
l’entité a les mêmes données que la BD
Peut être utile pour les transactions longues
13
find lock(A)
merge(A)
Entité détachée (2)
Si A est une entité détachée, son état est copié
Une entité détachée peut être modifiée dans une entité gérée A’ qui a la même identité
Pour que ces modifications soient que A (si A’ n’existe pas déjà, il est créé) ;
enregistrées dans la BD, il est nécessaire de merge renvoie A’
rattacher l’entité à un GE par la méthode Si A est nouvelle, une nouvelle entité gérée A'
merge est créé et l’état de A est copié dans A’
Si A est déjà gérée, merge est ignorée mais
merge « cascade » pour tous les associations
avec l’attribut CascadeType.MERGE
Si A est supprimée, une
IllegalArgumentException est lancée
R. Grin JPA page 83 R. Grin JPA page 84
14
merge(A)
15
Types de génération Précisions sur la génération
AUTO : le type de génération est choisi par le
Les annotations @SequenceGenerator et
fournisseur de persistance, selon le SGBD @TableGenerator permettent de donner
(séquence, table,…) ; valeur par défaut
plus de précisions sur la séquence ou la table
SEQUENCE : utilise une séquence est utilisée qui va permettre de générer la clé
IDENTITY : une colonne de type IDENTITY Par exemple @SequenceGenerator permet
est utilisée de préciser la valeur initiale ou le nombre de
TABLE : une table qui contient la prochaine clés récupérées à chaque appel de la
valeur de l’identificateur est utilisée séquence
On peut aussi préciser le nom de la séquence Voir la spécification de JPA pour plus de
ou de la table avec l’attribut generator précisions
R. Grin JPA page 91 R. Grin JPA page 92
n @EmbeddedId et @Embeddable
16
Exemple avec @EmbeddedId @IdClass
@Entity
public class Employe { @IdClass correspond au cas où la classe
@EmbeddedId entité comprend plusieurs attributs annotés
private EmployePK employePK; par @Id
...
La classe entité est annotée par @IdClass
}
qui prend en paramètre le nom de la classe
@Embeddable
public class EmployePK {
clé primaire
private String nom; La classe clé primaire n’est pas annotée ; ses
private Date dateNaissance; attributs ont les mêmes noms et mêmes
... types que les attributs annotés @Id dans la
} classe entité
R. Grin JPA page 97 R. Grin JPA page 98
Généralités
Une association peut être uni ou
bidirectionnelle
Elle peut être de type 1:1, 1:N, N:1 ou M:N
Associations Les associations doivent être indiquées par
une annotation sur la propriété
correspondante, pour que JPA puisse les
gérer correctement
17
Exemple Représentation des associations
1:N et M:N
@ManyToOne
public Departement getDepartement() { Elles sont représentées par des collections ou
... maps qui doivent être déclarées par un des
}
types interface suivants (de java.util) :
n Collection
n Set
n List
n Map
@OrderBy
Exemples
Cette annotation indique dans quel ordre sont
récupérées les entités associées @Entity
Il faut préciser un ou plusieurs attributs qui public class Departement {
déterminent l'ordre ...
@OneToMany(mappedBy="departement")
Chaque attribut peut être précisé par ASC ou
@OrderBy("nomEmploye")
DESC (ordre ascendant ou descendant);
ASC par défaut public List<Employe> getEmployes() {
...
Les différents attributs sont séparés par une
virgule
@OrderBy("poste DESC, nomEmploye ASC")
Si aucun attribut n'est précisé, l'ordre sera
celui de la clé primaire
R. Grin JPA page 107 R. Grin JPA page 108
18
Associations bidirectionnelles Bout propriétaire
Le développeur est responsable de la gestion Pour les associations autres que M:N ce bout
correcte des 2 bouts de l’association correspond à la table qui contient la clé
Par exemple, si un employé change de étrangère qui traduit l’association
département, les collections des employés Pour les associations M:N le développeur
des départements concernés doivent être peut choisir arbitrairement le bout propriétaire
modifiées L’autre bout (non propriétaire) est qualifié par
Un des 2 bouts est dit « propriétaire » de l’attribut mappedBy qui donne le nom de
l’association l’attribut dans le bout propriétaire qui
correspond à la même association
Dans la classe Departement : Sans cette annotation, le nom est défini par
@OneToMany(mappedBy="departement") défaut :
public Collection<Employe> getEmployes() { <entité_but>_<clé_primaire_entité_but>
return employes;
}
19
Pas si simple Le choix de JPA
Maintenir une cohérence automatique des Par défaut, JPA n’effectue pas de persistance
valeurs persistantes n’est pas si simple en par transitivité
cas de persistance par transitivité Ce comportement permet plus de souplesse,
Par exemple, que se passe-t-il si un objet et un meilleur contrôle de l’application sur ce
supprimé est référencé par un autre objet ? qui est rendu persistant
Pour que les objets associés à un objet
persistant deviennent automatiquement
persistants, il faut l’indiquer dans les
informations de mapping de l’association
(attribut cascade)
R. Grin JPA page 115 R. Grin JPA page 116
20
Exemple Cas particulier
class Employe {
... Une association monodirectionnelle 1:N est
@ManyToOne
public Departement getDepartement() { traduite pas une table association
... Cette façon de faire évite d'avoir une clé
} étrangère dans la table qui représente le côté
}
class Departement {
« N » (comme c’est le cas si l’association est
... bidirectionnelle) alors que la navigation n’est
@OneToMany(MappedBy="departement") pas possible à partir de ce côté « N »
public List<Employe> getEmployes() {
...
}
}
21
Exemple (classe Employe) Exemple (classe Projet)
@ManyToMany @ManyToMany(mappedBy="projets")
@JoinTable( public Collection<Employe> getEmps() {
name="EMP_PROJET"
joinColumns=@JoinColumn(name="matr")
inverseJoinColumns=
@JoinColumn(name="codeProjet")
)
public Collection<Projet> getProjets() {
22
Exemple - 2 identificateurs (2) Exemple - 2 identificateurs
avec TopLink
En ce cas, la solution est plus complexe, et La solution donnée dans les transparents
pas toujours portable dans l'état actuel de la suivants convient pour TopLink essentials
spécification JPA
La difficulté vient de l'écriture de la classe
La solution donnée dans les transparents Participation
suivants convient pour TopLink essentials
L'idée est de dissocier la fonction
La difficulté vient de l'écriture de la classe d'identificateur des attributs employeId et
Participation projetId de leur rôle dans les associations
L'idée est de dissocier la fonction de clé avec les classes Projet et Employe
primaire des attributs employeId et projetId Pour éviter les doublons d'attributs, les
de leur rôle dans les associations identificateurs sont marqués non modifiables
ni insérables (pas de persistance dans la BD)
R. Grin JPA page 133 R. Grin JPA page 134
23
Récupération des entités associées EAGER ou LAZY
JPA laisse le choix de récupérer ou non
Lorsqu’une entité est récupérée depuis la
base de données par une requête (Query) ou immédiatement les entités associées, suivant
par un find, est-ce que les entités associées les circonstances
doivent être elles aussi récupérées ? Il suffit de choisir le mode de récupération de
l’association (LAZY ou EAGER)
Si elles sont récupérées, est-ce que les entités
associées à ces entités doivent elles aussi Une requête sera la même, quel que soit le
être récupérées ? mode de récupération
On voit que le risque est de récupérer un très Dans le mode LAZY les données associées
grand nombre d’entités qui ne seront pas ne sont récupérées que lorsque c’est
utiles pour le traitement en cours vraiment nécessaire
R. Grin JPA page 139 R. Grin JPA page 140
24
Map pour association Map pour association
A la place d’une collection il est possible Si l’association est traduite par une map mais
d’utiliser une map n’a pas d’annotation @KeyMap, la clé sera
En ce cas il faut annoter l’association avec considérée être l’identificateur de l’entité
@MapKey qui précise la clé de la map qui doit
être un des attributs de l’entité contenue dans
la map
La classe de la clé doit avoir sa méthode
hashCode compatible avec sa méthode
equals et chaque clé doit être unique parmi
toutes les autres clés de la map
R. Grin JPA page 145 R. Grin JPA page 146
Exemple
Les employés d’un département peuvent être
enregistrés dans une map dont les clés sont
les noms des employés (on suppose que 2
employés n’ont pas le même nom)
Héritage
public class Departement {
...
@OneToMany(mappedBy="nom")
public Map<String,Employe> getEmployes(){
...
}
R. Grin JPA page 147 R. Grin JPA page 148
25
Exemple Nom de la table
@Entity A mettre dans la
classe racine de Si on choisit la stratégie « une seule table
@Inheritance(strategy= la hiérarchie pour une arborescence d’héritage » la table a
InheritanceType.SINGLE_TABLE) le nom de la table associée à la classe racine
public abstract class Personne {...} de la hiérarchie
@Entity
« Employe » par défaut
@DiscriminatorValue("E")
public class Employe extends Personne {
...
}
26
Une table par classe Exemple
Toutes les classes, même les classes
abstraites, sont représentées par une table @Entity
@Inheritance(strategy=
Nécessite des jointures pour retrouver les InheritanceType.JOINED)
propriétés d’une instance d’une classe public abstract class Personne {...}
Une colonne discriminatrice est ajoutée dans
la table qui correspond à la classe racine de @Entity
la hiérarchie d’héritage @DiscriminatorValue("E")
Cette colonne permet de simplifier certaines
public class Employe extends Personne {
...
requêtes ; par exemple, pour retrouver les }
noms de tous les employés (classe Personne
à la racine de la hiérarchie d’héritage)
R. Grin JPA page 157 R. Grin JPA page 158
27
Classe mère persistante Classe mère persistante
Une entité peut aussi avoir une classe mère Cette classe mère ne pourra pas être
dont l’état est persistant, sans que cette renvoyée par une requête, ne pourra pas être
classe mère ne soit une entité passée en paramètre d’une méthode d’un
En ce cas, la classe mère doit être annotée EntityManager ou d’un Query et ne pourra
par @MappedSuperclass être le but d’une association
L’état de cette classe mère sera rendu
persistant avec l’état de la classe entité fille,
dans la même table que cette classe entité
Exemple :
Departement dept =
em.find(Departement.class, 10);
R. Grin JPA page 167 R. Grin JPA page 168
28
getReference Étapes pour récupérer des données
getReference peut être (rarement) utilisée Souvent il est nécessaire de rechercher des
données sur des critères plus complexes que
pour améliorer les performances quand une
la simple identité
entité non initialisée peut être suffisante, sans
que l’entité entière soit retrouvée dans la base Les étapes sont alors les suivantes :
de données 1. Décrire ce qui est recherché (langage
29
Type du résultat Obtenir le résultat de la requête
L’expression de la clause select peut être Pour le cas où une seule valeur ou entité est
n une (ou plusieurs) expression « entité »,
renvoyée, le plus simple est d’utiliser la
par exemple un employé (e par exemple) méthode getSingleResult() ; elle renvoie
un Object
n une (ou plusieurs) expression « valeur »,
par exemple le nom et le salaire d’un
employé (e.nom par exemple)
L’expression ne peut être une collection
(d.employes par exemple), bien que
TopLink le permette !
30
Méthodes de Query (1) Méthodes de Query (2)
List getResultList() Query setParameter(String nom,
Object getSingleResult() Object valeur)
int executeUpdate() Query setParameter(String nom,
Query setMaxResults(int
Date valeur, TemporalType
nbResultats) typeTemporel)
Query setParameter(String nom,
Query setFirstResult(int
positionDepart) Calendar valeur, TemporalType
typeTemporel)
Query setFlushMode(FlushModeType
modeFlush)
31
Paramètres des requêtes Exemples
Un paramètre peut être désigné par son Query query = em.createQuery(
numéro (?n) ou par son nom (:nom) "select e from Employe as e "
+ "where e.nom = ?1");
Les valeurs des paramètres sont données query.setParameter(1, "Dupond");
par les méthodes setParameter Query query = em.createQuery(
Les paramètres sont numérotés à partir de 1 "select e from Employe as e "
+ "where e.nom = :nom");
Un paramètre peut être utilisé plus d’une fois
query.setParameter("nom", "Dupond");
dans une requête
L’usage des paramètres nommés est
recommandé (plus lisible)
Mode de flush
Normalement (mode FlushMode.AUTO) un Les transparents suivants étudient en détails
flush des entités concernées par une requête le langage JPQL
est effectué avant la requête pour que le
résultat tienne compte des modifications
effectuées en mémoire sur ces entités
Pour une requête il est possible d'éviter ce
flush avec la méthode setFlushMode :
query.setFlushMode(FlushMode.COMMI
T);
32
Polymorphisme dans les requêtes Expression de chemin
Toutes les requêtes sont polymorphes : un Les requêtes peuvent contenir des
nom de classe dans la clause from désigne expressions de chemin pour naviguer entre
cette classe et toutes les sous-classes les entités en suivant les associations
Exemple : déclarées dans le modèle objet (les
select count(a) from Article as a annotations @OneToOne, @OneToMany, …)
compte le nombre d’instances de la classe La notation « pointée » est utilisée
Article et de tous les sous-classes de
Article
Exemples distinct
Si e est un alias pour Employe, Dans une clause select, indique que les
n « e.departement » désigne le valeurs dupliquées sont éliminées (la requête
département d’un employé ne garde qu’une seule des valeurs égales)
n « e.projets » désigne la collection de Exemple :
projets auxquels participe un employé select distinct e.departement
select e.nom from Employe e
from Employe as e
where e.departement.nom = 'Qualité'
33
Exemple having
select d.nom, avg(e.salaire) Restriction : la condition doit porter sur
from Departement d join d.employes e l’expression de regroupement ou sur une
group by d.nom fonction de regroupement portant sur
having count(d.nom) > 3 l’expression de regroupement
Par exemple, la requête suivante provoque
une exception :
select d.nom, avg(e.salaire)
from Departement d join d.employes e
group by d.nom
having avg(e.salaire) > 1000
34
Règle pour les expressions Exemple
de chemin
select e.nom,
e.departement.nom,
Une navigation peut être chaînée à une e.superieur.departement.nom
navigation précédente à la condition que la from Employe e
navigation précédente ne donne qu’une seule
entité (OneToOne ou ManyToOne)
Contre-exemple Jointure
« d.employes.nom » est interdit car Une jointure permet de combiner plusieurs
d.employes est une collection entités dans un select
Pour avoir les noms des employés d’un Rappel : il est possible d’utiliser plusieurs
département, il faut utiliser une jointure entités dans une requête grâce à la
navigation
Une jointure est le plus souvent utilisée pour
résoudre les cas (interdit par JPA) où
n l’expression du select serait une collection
35
Autres exemples Jointure externe
select e.nom
from Departement d select e, d
join d.employes e from Employe e left join e.departement d
where d.nom = 'Direction'
affichera aussi les employés qui ne sont pas
select e.nom, parts.projet.nom
from Employe e associés à un département
join e.participations parts
select e.nom, d.nom
from Employe e, Departement d
where d = e.departement
select e, p
from Employe e
join e.participations parts
join parts.projet p
R. Grin JPA page 211 R. Grin JPA page 212
L’entité placé à droite de fetch join sera Cette requête récupérera tous les employés
créée en mémoire en même temps que mais, en plus, l’appel de la méthode
l’entité de la clause select getDepartement() ne provoquera aucune
interrogation de la base de données puisque
Le select SQL généré sera une jointure
le « join fetch » aura déjà chargé tous les
externe qui récupérera les données de toutes
départements des employés
les entités associées en même temps que les
données des entités principales de la requête L’exemple suivant précharge les collections
de participations aux projets
R. Grin JPA page 213 R. Grin JPA page 214
36
Fonctions Travail avec les collections
Fonctions de chaînes de caractères : concat,
substring, trim, lower, upper, length, locate Une expression chemin d’un select peut
(localiser une sous-chaîne dans une autre) désigner une collection
Exemples :
Fonctions arithmétiques : abs, sqrt, mod, size
departement.employes
(d’une collection)
facture.lignes
Fonctions de date : current_date, current_time,
La fonction size donne la taille de la collection
current_timestamp
La condition « is [not] empty » est vraie si
Fonctions de regroupement : count, max, min,
avg la collection est [n’est pas] vide
La condition « [not] member of » indique si
Pour plus d’informations, consultez la
spécification JPA une entité appartient à une collection
R. Grin JPA page 217 R. Grin JPA page 218
37
Pagination du résultat
Query setMaxResults(int n) : indique
le nombre maximum de résultats à retrouver
Query setFirstResult(int n) : indique Opération de modification
la position du 1er résultat à retrouver
(numéroté à partir de 0)
en volume
Exemple Syntaxe
em.getTransaction().begin(); Les ordres de modification en volume
String ordre = référencent les classes et les propriétés des
"update Employe e " + classes mais ils ne créent aucune entité en
" set e.salaire = e.salaire * 1.05"; mémoire et ils ne mettent pas à jour les entités
Query q = em.createQuery(ordre);
déjà présentes en mémoire
int nbEntiteModifiees =
q.executeUpdate(); update Entite as alias
em.getTransaction().commit(); set alias.prop1 = val1, alias.prop2 = val2,…
where condition
La condition peut être aussi complexe que la
condition d’un select
38
Remarques
Les modifications doivent être faites dans une
transaction
Le 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 Exceptions
d’une transaction avant la récupération dans la
base d’entités touchées par l’opération
En 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
R. Grin JPA page 229 R. Grin JPA page 230
2 types de transactions
Les transactions locales à une ressource,
fournies par JDBC sont attachées à une
seule base de données
Transaction Les transactions JTA, avec plus de
fonctionnalités que les transactions JDBC, en
particulier elles peuvent travailler avec
plusieurs bases de données
39
Transactions dans Java EE Transactions dans Java SE
(sans serveur d’applications)
Elles sont étudiées dans la dernière section
de ce support de cours 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
supporter les transactions JTA
La démarcation des transactions est choisie
par le développeur
Les contextes de persistance peuvent couvrir
plusieurs transactions
R. Grin JPA page 235 R. Grin JPA page 236
EntityTransaction EntityTransaction
40
Rollback (2) Transaction et contexte
de persistance
Les instances d’entités Java gardent les
valeurs qu’elles avaient au moment du rollback Quand un GE n’est pas géré par un container
Mais ces valeurs sont le plus souvent fausses
le contexte de persistance n’est pas fermé à
la fin d’une transaction
Il est donc rare d’utiliser ces entités en les
rattachant par un merge à un GE Quand un GE est géré par un container et
que le contexte de persistance n’est pas de
Le plus souvent il faut relancer des requêtes
type « étendu », le contexte est fermé à la fin
pour récupérer des entités avec des valeurs
d’une transaction (voir à la fin de ce support)
correctes
GE et threads
Une fabrique de GE peut être utilisée sans
problème par plusieurs threads
Mais un GE ne doit être utilisé
Concurrence concurremment que par un seul thread
41
Entités et threads Concurrence « BD »
Les entités ne sont pas prévues pour être Le fournisseur de persistance peut apporter
utilisées par plusieurs threads en même temps automatiquement une aide pour éviter les
Si ça doit être le cas, l’application doit prendre problèmes d’accès concurrents aux données
toutes ses précautions pour éviter les de la BD, pour les entités gérées par un GE
problèmes
C’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 temps
Le rôle du fournisseur de persistance
n’intervient pas pour ces cas
R. Grin JPA page 247 R. Grin JPA page 248
@version Exemple
Annote un attribut dont la valeur représentera
@Version
un numéro de version (incrémenté à chaque
private int version;
modification) pour l’entité et sera utilisée pour
savoir si l’état d’une entité a été modifiée entre
2 moments différents (stratégie optimiste)
L’attribut doit être de type int, Integer,
short, Short, long, Long ou
java.sql.TimeStamp (si possible, éviter ce
dernier type)
L’application ne doit jamais modifier un tel
attribut (modifié par JPA)
R. Grin JPA page 251 R. Grin JPA page 252
42
Entité « versionnée » lock(A, mode)
C’est une entité qui possède un attribut qui Sert à protéger une entité contre les accès
possède l’annotation @version (ou le tag concurrents pour les cas où la protection
correspondant dans les fichiers XML) offerte par défaut par le fournisseur ne suffit
pas
Cette entité doit être versionnée (sinon, le
traitement n’est pas portable)
43
WRITE Utilité des blocages WRITE (1)
Évite en quelque sorte les problèmes de Une entête de facture contient un champ dans
lignes fantômes avec les associations qui lequel est stocké le total de la facture
concernent une entité Supposons que le calcul de ce total est
En effet, le fournisseur de persistance effectué par un processus à part du processus
incrémente automatiquement le numéro de de l’ajout des lignes de la facture
version si une entité est modifiée mais pas si Lorsqu’une ligne de facture est ajoutée à une
les liens des associations qui partent de facture, l’en-tête de la facture n’est pas
l’entité sont modifiées modifiée donc le fournisseur de persistance
n’incrémente pas le numéro de version de
l’en-tête
R. Grin JPA page 259 R. Grin JPA page 260
Cas d’utilisation
Le serveur d’application récupère des
données dans la BD
Ces données sont montrées à l’utilisateur et
Entité détachée celui-ci peut les modifier
Les modification sont repassées au serveur
et enregistrées dans la BD
Les entités détachées facilitent
l’implémentation d’un tel cas d’utilisation
44
EJB 2.0 EJB 3.0
Dans la norme EJB 2.0, les données de la BD Plus ce problème dans la norme EJB 3.0
étaient enregistrées dans un objet EJB entité Les entités peuvent être détachées de leur
Le problème était qu’un objet entité ne contexte de persistance d’origine et
pouvait exister que dans l’environnement du rattachées par la suite
serveur d’application
Les données était donc souvent passées au
client sous forme de DTO (pour éviter de
nombreux appels distants aux EJB entités,
qui sont coûteux)
45
État d’une entité État d’une entité
En effet, pour des raisons de performances, Un attribut persistant d’une entité est
une entité gérée par un GE (attachée) peut ne immédiatement disponible dans les 2 cas
récupérer dans la BD qu’une partie de son état suivants :
Le reste de l’état ne sera récupéré que lorsque n l’attribut a déjà été utilisé
l’entité en aura vraiment besoin, avec l’aide du n l’attribut n’a pas été marqué par
GE fetch=LAZY
Si 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
R. Grin JPA page 271 R. Grin JPA page 272
En ce cas, une fois détachée et loin du GE, la join fetch lors d’une requête
norme n’assure pas que l’entité puisse
récupérer l’état manquant
R. Grin JPA page 273 R. Grin JPA page 274
46
Entité détachée et concurrence Conflit de concurrence
Avant que les modifications sur l’entité Si les données de la BD associée à un objet
détachée ne soient enregistrées dans la BD, détaché ont été modifiées depuis le
l’entité doit être rattachée à un contexte de détachement de l’objet, merge lance une
persistance (celui d’origine ou un autre) exception, ou le commit échouera
A ce moment, ou au moment du commit qui Tout se passe donc comme si un conflit de
enregistre vraiment les modifications, le concurrence avait été détecté (avec une
contexte de persistance vérifie qu’il n’y a pas stratégie optimiste)
de conflit de concurrence
47
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é
Callback passera dans une nouvelle étape de son
cycle de vie
Ces méthodes peuvent appartenir à une
classe entité (entity ou classe mère
« mapped ») ou à une classe « écouteur »
48
Configuration d’une unité de persistence.xml
persistance <persistence
xmlns="http://java.sun.com/xml/ns/persistence"
Les informations indiquent comment se version= "1.0" >
connecter à la base de données, ainsi que <persistence-unit name="Employes"
d’autres informations, comme les noms des transaction-type="RESOURCE_LOCAL">
classes entités, la configuration de <class>p1.Employe</class>
l’environnement de mis au point (logging, <class>p1.Dept</class>
affichage des ordres SQL lancés dans le <properties>
SGBD,…) ou des propriétés particulières au . . . <!– Voir transparent suivant-->
driver du fournisseur de persistance </properties>
</persistence-unit>
</persistence>
R. Grin JPA page 289 R. Grin JPA page 290
49
Exemple
<properties> toplink.ddl-generation.output-mode
. . . indique ce qui sera fait avec les fichiers DDL
<property name="toplink.ddl-generation" Valeurs possibles :
value="drop-and-create-tables"/>
n sql-script génère les fichiers mais ne
</properties>
les exécute pas
n database exécute les ordres DDL mais
50
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
Fichiers XML classpath
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
</mapping-file> Inconvénients :
</persistence-unit> n changement des méta données nécessite
une recompilation
Les informations données dans les fichiers
XML l’emportent sur les annotations
R. Grin JPA page 303 R. Grin JPA page 304
51
JPA dans les serveurs
Types de gestionnaires d’entités
d’applications
52
GE géré par le container (3) Contexte de persistance de
portée limitée à une transaction
L’application peut gérer elle-même la création Dans le cas d’un contexte de persistance de
d’un GE en utilisant une fabrique de GE portée limitée à une transaction (pas le cas si
(méthode createEntityManager()) application en dehors d’un container),
La fabrique de gestionnaires d’entités n persist, merge, remove et refresh
s’obtient par injection de ressource (fournie doivent être invoquées dans le contexte
par le serveur d’applications) : d’une transaction
@PersistenceUnit n find et getReference (comme les
Transactions
Une requête peut être lancée en dehors de
toute transaction
Dans le cas où le contexte de persistance est
limité à une transaction, les entités seront Types de transactions
détachées (non gérées par un GE)
53
Transactions gérées par l’application Environnement par défaut
disponibles dans Java EE dans un serveur d’applications
Le code utilise l’interface Contexte de persistance géré par le container
javax.transaction.UserTransaction (injecté par annotation ou par lookup JNDI)
qui possède des méthodes pour démarrer, Contexte de persistance limité à une seule
terminer ou marquer pour invalidation une transaction
transaction JTA
Transaction JTA dont les démarcations sont
Une instance de UserTransaction peut
fixées déclarativement (par annotation ou
être injectée par une annotation @Resource
dans un fichier XML)
54
Définition Définition
Un contexte de persistance peut être propagé
Association d’un contexte de persistance
durant une transaction JTA s’il est utilisé par
avec une transaction JTA : le contexte de
des GEs gérés par le container
persistance est lié à la transaction ; le
contexte devient le contexte actif lié à la Ce contexte est alors utilisé à tour de rôle
transaction durant la transaction par les GEs
Cette association va permettre au container Cette propagation s’appelle une propagation
de retrouver un contexte de persistance en de contexte
interrogeant la transaction, et donc de Quand un GE reçoit un message, il vérifie s’il
permettre la propagation de contexte existe un contexte propagé ; si c’est le cas, il
utilise celui-ci, sinon il en crée un nouveau
R. Grin JPA page 325 R. Grin JPA page 326
55
Conversation longue (1) Conversation longue (2)
L'utilisation d'un contexte étendu permet On peut commencer par une transaction,
d'implémenter des conversations longues valider la transaction, passer des données au
entre un client et un bean session avec état client qui les modifie et ensuite reprendre une
Il n'est pas indispensable, et souvent néfaste, autre transaction pour terminer la conversation
qu'une seule transaction longue couvre toute Dès que la 2ème transaction démarre, toutes
la conversation les modifications faites entre les 2 transactions
sont prises en compte par cette 2ème
transaction
joinTransaction
56
Livre
Pro EJB 3 – JPA
de Mike Keith et Merrick Schincariol
Edition Apress
(en anglais)
57