Introduction

publicité
JPA
Java Persistence API
Université de Nantes
&
Ecole des Mines de Nantes
Laurent Guérin / V 1.2 / Novembre 2015
Introduction
JPA - Java Persistence API
1
De JDBC à JPA
Pendant longtemps la plate-forme Java n’a disposé
que d’une API de bas niveau pour gérer l’accès aux
bases de données relationnelles :
JDBC ( Java DataBase Connectivity )
Implémentations
Oracle
JDBC
Oracle
Application
Spécification
MySQL
API
JSR 221
JDBC 4.0
Sybase
JPA – Java Persistence API ( Laurent Guérin / v 1.2 / www.laurent-guerin.fr )
MySQL
Sybase
etc
…
…
3
De JDBC à JPA
JDBC
Orienté base de données relationnelle
Permet d’utiliser des requêtes SQL pour consulter et mettre
à jour des « records » dans des « tables »
API de « bas niveau » (gestion des connexions, des
requêtes SQL, des « ResultSet », etc… )
Des frameworks de plus haut niveau sont apparus :
Hibernate, TopLink, iBatis, …
Une nouvelle spécification a été ajoutée dans la
plate-forme Java : JDO (+/- échec)
JDO 1.0 – JSR 12 ( 2002 )
JDO 2.0 – JSR 243 ( fin 2005 )
JPA – Java Persistence API ( Laurent Guérin / v 1.2 / www.laurent-guerin.fr )
JPA - Java Persistence API
4
2
De JDBC à JPA
Sous l’influence des frameworks de type « ORM »
(Object Relational Mapping) et pour répondre aux
nombreuses critiques concernant les EJB, une
nouvelle spécification est proposée et adoptée :
JPA ( Java Persistence API )
JPA 1.0
Java EE 5 ( JSR 220 / EJB 3.0 ) – Mai 2006
JPA 2.0
Java EE 6 ( JSR 317 ) – Déc. 2009
JPA 2.1
Java EE 7 ( JSR 338 ) – Mai 2013
JPA – Java Persistence API ( Laurent Guérin / v 1.2 / www.laurent-guerin.fr )
5
Différents niveaux d’API de persistance
ORM : JPA (ou Hibernate, TopLink, …) …
Haut niveau, « Orienté Objet »
Tente de cacher la complexité du mapping
NB : concepts sous-jacents souvent mal compris
par les développeurs ( "lazy/eager" loading, effets de
cache, "attached/detached" entities, "owning
side"/"inverse side" links, … )
Record
Autres API
Niveau intermédiaire
JDBC API
Bas niveau, « Orienté Record & SQL »
Adresse directement la structure de la
base en SQL
JPA – Java Persistence API ( Laurent Guérin / v 1.2 / www.laurent-guerin.fr )
JPA - Java Persistence API
Record
6
3
Exemple JDBC
Connection conn = null;
try {
SLQ natif
conn = getConnection() ;
PreparedStatement ps = conn.prepareStatement(
"SELECT .. FROM EMPLOYEE WHERE ..." );
ResultSet rs= ps.executeQuery();
while (rs.next()) {
employee.setId( rs.getInt(1) );
Mapping
employee.setName ( rs.getString(2) );
manuel
}
rs.close();
} catch (SQLException e) {
// ...
} finally {
if ( conn != null ) {
try {
conn.close();
Gestion de la
} catch (Exception ex) {
connexion
// ...
}
}
}
JPA – Java Persistence API ( Laurent Guérin / v 1.2 / www.laurent-guerin.fr )
7
Exemple ORM ( JPA )
Liste d’employés :
static String displayAllQuery = "Select emp from Employee emp" ;
TypedQuery e = em.createQuery(displayAllQuery, Employee.class);
List <Employee> employees=e.getResultList();
for ( Employee emp : employees ) {
// ...
}
Un employé :
Employee e = (Employee) em.find(Employee.class, id);
Moins de code
Les connexions
sont masquées
Mapping automatique
sur la classe Employee
JPA – Java Persistence API ( Laurent Guérin / v 1.2 / www.laurent-guerin.fr )
JPA - Java Persistence API
8
4
Pourquoi JPA ?
Pourquoi utiliser JPA plutôt que TopLink ou Hibernate
ou autre ?
JPA fait partie de la plate-forme Java EE
JPA est normalisé
JPA 1.0
JPA 2.0
JSR 220 / EJB 3 ( Java EE 5 )
JSR 317 ( Java EE 6 )
Cependant, certains frameworks de persistance
peuvent offrir des possibilités supplémentaires
Exemple :
Norme
JPA 2.0
Hibernate
JPA – Java Persistence API ( Laurent Guérin / v 1.2 / www.laurent-guerin.fr )
9
Spécification et implémentations
Application
JPA 2.0 Specification
Hibernate
TopLink
Open JPA
API
JSR 317
Eclipse Link
Autres
…
( R.I. )
Implémentations
JPA – Java Persistence API ( Laurent Guérin / v 1.2 / www.laurent-guerin.fr )
JPA - Java Persistence API
10
5
Implémentations & versions
JPA
Java EE
Hibernate
JPA 1.0
Java EE 5
Hibernate ORM 3.2 +
EclipseLink
JPA 2.0
Java EE 6
Hibernate ORM 3.5 +
EclipseLink 2.2
2.4
JPA 2.1
Java EE 7
Hibernate ORM 4.3 +
EclipseLink 2.5
2.6
Cf :
• http://hibernate.org/orm/downloads/
• https://eclipse.org/eclipselink/downloads/
Maven POM pour Hibernate 4.3.11 :
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-entitymanager</artifactId>
<version>4.3.11.Final</version>
</dependency>
JPA – Java Persistence API ( Laurent Guérin / v 1.2 / www.laurent-guerin.fr )
11
Mapping
Objet / Relationnel
JPA - Java Persistence API
6
Problématique du mapping « O / R »
Problème :
« Modèle Objet »
≠
« Modèle Relationnel »
Base de
données
Relationnelle
Graphe
d’ objets
?
. Instances de classes
. Références (graphe)
. « clé primaire » pas obligatoire
. Héritage
. Records dans des tables
. Relations (FK
PK )
JPA – Java Persistence API ( Laurent Guérin / v 1.2 / www.laurent-guerin.fr )
13
Mapping simple
Animal.java
. Int
id
. String nom
. float prix
1 classe
JPA – Java Persistence API ( Laurent Guérin / v 1.2 / www.laurent-guerin.fr )
JPA - Java Persistence API
ANIMAL
ID
NOM
PRIX
1 table
14
7
Exemple de mapping
Exemple de mapping avec « Telosys Tools Eclipse Plugin » :
Base de données
Objet ( Java )
http://marketplace.eclipse.org/content/telosys-tools
JPA – Java Persistence API ( Laurent Guérin / v 1.2 / www.laurent-guerin.fr )
15
Le cas de l’héritage
ANIMAL
. nom
. prix
CHAT
. tatouage
POISSON
. flag_eau_douce
Cas classique d’héritage : 3 possibilités :
Héritage vertical
Héritage horizontal
Filtrage par type
=> 3 tables
=> 2 tables
=> 1 seule table
JPA – Java Persistence API ( Laurent Guérin / v 1.2 / www.laurent-guerin.fr )
JPA - Java Persistence API
16
8
Le cas de l’héritage
Héritage vertical :
ANIMAL
id
nom
prix
Coût des jointures
CHAT
id (FK)
tatouage
POISSON
id (FK)
flag_eau_douce
Remarques :
. On choisit en fonction
des contraintes (performances,
normes,… )
. Souvent le modèle physique
(relationnel) existe déjà !
Filtrage par type :
ANIMAL
Héritage horizontal :
CHAT
id
nom
prix
tatouage
POISSON
id
nom
prix
flag_eau_douce
Pb d’unicité de l’id
Réplication des attributs (nom, prix,…)
id
type (chat/poisson)
nom
prix
tatouage
flag_eau_douce
Mélange des genres
JPA – Java Persistence API ( Laurent Guérin / v 1.2 / www.laurent-guerin.fr )
17
Les grands principes
de JPA
JPA - Java Persistence API
9
Objectif : rester au niveau objet
JPA donne l’impression au développeur de travailler
avec une base de données
JPA
orientée objet
( « object database » )
JPA masque toute la
« plomberie » relationnelle
Les connexions à la base de données ne
sont pas visibles ( objets JDBC « Connection » )
Dans les cas usuels le développeur n’utilise
SQL
jamais le SQL (l’utilisation de requêtes SQL
natives reste cependant possible pour les cas
particuliers)
JPA – Java Persistence API ( Laurent Guérin / v 1.2 / www.laurent-guerin.fr )
19
Mapping par annotations
BOOK
ID
TITLE
PRICE
un mapping par
fichier XML est
aussi possible
( orm.xml )
JPA – Java Persistence API ( Laurent Guérin / v 1.2 / www.laurent-guerin.fr )
JPA - Java Persistence API
20
10
Quelques objets pour tout gérer
Chaque base de données est une « Persistence
Unit » décrite dans un fichier de configuration XML
A chaque « Persistence Unit » correspond un
« EntityManagerFactory »
Les opérations de persistance reposent sur un objet
central : « EntityManager »
qui est fourni par l’ « EntityManagerFactory » de la
base de données à adresser
JPA – Java Persistence API ( Laurent Guérin / v 1.2 / www.laurent-guerin.fr )
21
Les principaux objets
EntityManager
PersistenceContext
EntityManager
PersistenceContext
EntityManager
PersistenceContext
EntityManager
PersistenceContext
EntityManagerFactory
PersistenceUnit
Fichier XML
« persistence.xml »
définit 1 à N PersistenceUnit
( paramètres de connexion
à la base de données, etc… )
JPA – Java Persistence API ( Laurent Guérin / v 1.2 / www.laurent-guerin.fr )
JPA - Java Persistence API
PersistenceUnit
22
11
JPA : une affaire de caches
« EntityManager » fournit des méthodes de gestion
d’objets stockés dans des caches, ce sont des
mécanismes internes qui gèrent les requêtes SQL
Vue « objet »
SQL
( masqué )
JPA – Java Persistence API ( Laurent Guérin / v 1.2 / www.laurent-guerin.fr )
23
Le fichier « persistence.xml »
Situé dans « META-INF »
<persistence version="2.0" xmlns=".. ..">
Nom
Implémentation
<persistence-unit
name="myunit"
JPA
transaction-type="RESOURCE_LOCAL">
<provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
<class>org.demo.entities.Badge</class> Classes des entités gérées
<class>org.demo.entities.Author</class> (facultatif pour Hibernate)
<properties>
<property name="javax.persistence.jdbc.driver"
value="org.apache.derby.jdbc.ClientDriver"/>
<property name="javax.persistence.jdbc.url"
value="jdbc:derby://localhost:1527/bookstore"/>
<property name="javax.persistence.jdbc.user"
value="root"/>
<property name="javax.persistence.jdbc.password"
value="admin"/>
</properties>
Configuration
de la
connexion
JDBC
</persistence-unit>
</persistence>
JPA – Java Persistence API ( Laurent Guérin / v 1.2 / www.laurent-guerin.fr )
JPA - Java Persistence API
24
12
Démarrage
Début et fin en Java SE :
persistence.xml
public static void main(String[] args)
{
Nom
EntityManagerFactory emf =
Persistence.createEntityManagerFactory("myunit");
// Récupération d’une instance de "EntityManager"
EntityManager em = emf.createEntityManager();
// Utilisation de l’ "EntityManager" ...
// Fermeture de l’ "EntityManager"
em.close();
emf.close();
}
JPA – Java Persistence API ( Laurent Guérin / v 1.2 / www.laurent-guerin.fr )
25
Le mapping O/R
avec JPA
JPA - Java Persistence API
13
JPA – Mapping O/R
Le mapping
JPA repose
sur des
annotations
définies dans
le package
« javax.persistence »
(cf JavaDoc )
JPA – Java Persistence API ( Laurent Guérin / v 1.2 / www.laurent-guerin.fr )
27
JPA – Mapping O/R
Mapping de l’entité (classe Java)
Association Classe
Table ( et « schéma » si nécessaire )
@Entity
@Table(name="EMP", schema="HR")
public class Employee { ... }
Mapping attribut Java
colonne de la table
@Entity
public class Employee {
@Id
@Column(name="EMP_ID")
private int id;
@Column(name="NAME")
private String name;
@Column(name="SAL")
private long salary;
...
JPA – Java Persistence API ( Laurent Guérin / v 1.2 / www.laurent-guerin.fr )
JPA - Java Persistence API
Les annotations peuvent
être placées au niveau
des champs ou au
niveau des accesseurs
( setXxxx )
28
14
JPA – Mapping O/R
ID ( Clé Primaire ) : @Id
@Id
@Column(name="EMP_ID")
private int id;
Types BLOB/CLOB : @Lob
@Basic(fetch=FetchType.LAZY)
@Lob
@Column(name="PIC")
private byte[] picture;
Les types de dates @Temporal
@Temporal(TemporalType.DATE)
@Column(name="START_DATE")
private Date startDate;
JPA – Java Persistence API ( Laurent Guérin / v 1.2 / www.laurent-guerin.fr )
.DATE
.TIME
.TIMESTAMP
29
JPA – Mapping O/R
Les annotations sont utilisées pour construire
les requêtes SQL
Requêtes SQL / JDBC
créées à partir des annotations :
Entité Java avec ses annotations :
JPA – Java Persistence API ( Laurent Guérin / v 1.2 / www.laurent-guerin.fr )
JPA - Java Persistence API
30
15
JPA – Mapping O/R
Un colonne ne peut être « mappée » que sur un seul
champ, sinon JPA ne sait pas quel champ de l’objet
doit être utilisé pour SQL « insert » et « update »
Erreur dès le chargement de la classe :
org.hibernate.MappingException: Repeated column in
mapping for entity: org.demo.basics.entities.EmployeeEntity
column: LAST_NAME
Sauf si on indique explicitement que l’un des champs
ne doit pas être utilisé pour les opérations « insert »
et/ou « update ». Exemple :
Champ « read only »
JPA – Java Persistence API ( Laurent Guérin / v 1.2 / www.laurent-guerin.fr )
31
JPA – Mapping O/R
Génération d’id
AUTO : c’est le provider JPA qui décide
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private int id;
TABLE : id stocké dans une table
@Id
@TableGenerator(name="EmpGen", table="x",
pkColumnName="x" , valueColumnName="x" )
@GeneratedValue( generator = "EmpGen" )
private int id;
SEQUENCE: id géré par une séquence
@Id
@SequenceGenerator(name="EmpGen", sequenceName="SEQ1")
@GeneratedValue( generator = "EmpGen" )
private int id;
IDENTITY : id généré par une colonne auto-incrémentée
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
JPA – Java Persistence API ( Laurent Guérin / v 1.2 / www.laurent-guerin.fr )
JPA - Java Persistence API
32
16
JPA – Mapping O/R – Links
Les types de liens JPA
Department
. ID
. NAME
Employee
Computer
OneToMany
OneToOne
. ID
. FIRST_NAME
ManyToOne . LAST_NAME
OneToOne
. DEPARTMENT_ID (FK)
. COMPUTER_ID (FK)
FK
. ID
. NAME
FK
ManyToMany
FK
ManyToMany
Emp_Proj
Project
. EMPLOYEE_ID (FK)
. PROJECT_ID (FK)
FK
Link ( owning side)
Link ( inverse side )
. ID
. NAME
"Join table"
JPA – Java Persistence API ( Laurent Guérin / v 1.2 / www.laurent-guerin.fr )
33
JPA – Mapping O/R – Links
Une relation entre 2 entités repose sur 2 liens
( un lien pour chaque sens )
Chaque lien à un sens et une cardinalité :
One To One,
One To Many,
Many To One,
Many To Many
Owning Side
Le côté « propriétaire » du lien
Celui qui possède la Foreign Key
Inverse Side
Le côté « référencé » par le « propriétaire »
« The owner has the power »
JPA – Java Persistence API ( Laurent Guérin / v 1.2 / www.laurent-guerin.fr )
JPA - Java Persistence API
34
17
JPA – Mapping O/R – Links
Exemple
JPA – Java Persistence API ( Laurent Guérin / v 1.2 / www.laurent-guerin.fr )
35
JPA – Mapping O/R – Links
Exemple : Many To One ( Owning Side )
@Entity
public class Employee {
@Id
private int id;
@ManyToOne
@JoinColumn(name="DEPARTMENT_ID")
private Department department;
// ...
ONE :
simple référence
sur une entité
}
Department
. ID
. NAME
Employee
OneToMany
. ID
. FIRST_NAME
ManyToOne . LAST_NAME
. DEPARTMENT_ID (FK)
. COMPUTER_ID (FK)
FK
JPA – Java Persistence API ( Laurent Guérin / v 1.2 / www.laurent-guerin.fr )
JPA - Java Persistence API
36
18
JPA – Mapping O/R – Links
Exemple : One To Many ( Inverse Side )
@Entity
public class Department {
@Id
private int id;
Attribut qui pointe
sur cette entité
dans l’Owning Side
private String name;
@OneToMany(mappedBy="department")
private Collection<Employee> employees;
// ...
MANY :
Collection
}
Department
. ID
. NAME
Employee
OneToMany
. ID
. FIRST_NAME
ManyToOne . LAST_NAME
FK
JPA – Java Persistence API ( Laurent Guérin / v 1.2 / www.laurent-guerin.fr )
. DEPARTMENT_ID (FK)
. COMPUTER_ID (FK)
37
JPA – Mapping O/R – Links
Exemple : Many To Many
@Entity
public class Employee {
@Id
private int id;
//...
Owning Side
(choix arbitraire)
@ManyToMany
@JoinTable( name="EMP_PROJ",
joinColumns=@JoinColumn(name="EMPLOYEE_ID"),
inverseJoinColumns=@JoinColumn(name="PROJECT_ID") )
private Collection<Project> projects;
Inverse Side
// ...
}
JPA – Java Persistence API ( Laurent Guérin / v 1.2 / www.laurent-guerin.fr )
JPA - Java Persistence API
38
19
JPA – Mapping O/R – Loading
Lorsqu’une entité est chargée dans le
« PersistenceContext », ses liens peuvent être
immédiatement chargés : « Eager Loading »
chargés plus tard, uniquement quand
l’application va les utiliser : « Lazy Loading »
@Entity
public class Employee {
@Id
private int id;
@OneToOne(fetch=FetchType.LAZY)
private ParkingSpace parkingSpace;
// ...
}
JPA – Java Persistence API ( Laurent Guérin / v 1.2 / www.laurent-guerin.fr )
39
JPA – Mapping O/R – Autres exemples
Lien basé sur une seule colonne
@ManyToOne
@JoinColumn (name="ADDR_ID", referencedColumnName="ID")
public Address getAddress() { return address; }
Lien basé sur deux colonnes
@ManyToOne
@JoinColumns (
@JoinColumn
@JoinColumn
} )
public Address
{
(name="ADDR_ID", referencedColumnName="ID") ,
(name="ADDR_ZIP", referencedColumnName="ZIP")
getAddress() { return address; }
JPA – Java Persistence API ( Laurent Guérin / v 1.2 / www.laurent-guerin.fr )
JPA - Java Persistence API
40
20
JPA – Mapping O/R – Autres exemples
« join table » avec clé composite
@ManyToMany
@JoinTable(
name="EMP_PROJECT",
joinColumns = {
@JoinColumn (name="EMP_COUNTRY", referencedColumnName="COUNTRY"),
@JoinColumn (name="EMP_ID", referencedColumnName="EMP_ID") },
inverseJoinColumns = @JoinColumn(name="PROJECT_ID")
)
private Collection<Project> projects;
JPA – Java Persistence API ( Laurent Guérin / v 1.2 / www.laurent-guerin.fr )
41
Architecture de JPA
JPA - Java Persistence API
21
Le contexte de persistance
Le « PersistenceContext » est un espace de
stockage en mémoire qui contient des « entités »
Chaque entité a un état et est identifiée par sa clé
primaire ( il ne peut pas y avoir 2 instances d’une
même classe avec la même clé primaire )
PersistenceContext
Entity
primary key
state
Entity
primary key
state
EntityManager
Entity
primary key
state
Entity
primary key
state
Entity
primary key
state
JPA – Java Persistence API ( Laurent Guérin / v 1.2 / www.laurent-guerin.fr )
43
Le contexte de persistance
L’ « EntityManager » gère l’état des instances dont
il a la charge ( objets « Managed » dans le
« PersistenceContext » )
Il décide quand et comment répercuter les mises à
jour dans la base données
EntityManager
persist(e1)
Entity 1
remove(e1)
Entity 1
persist(e2)
Entity 2
+
Mises à jour
différées
+
tx.commit()
SQL :
INSERT e2
1 seul insert
JPA – Java Persistence API ( Laurent Guérin / v 1.2 / www.laurent-guerin.fr )
JPA - Java Persistence API
44
22
Gestion des entités
Entity
primary key
« New »
Entity
primary key
« Detached/New »
em.persist(e)
em.clear()
em.detach(e)
em.close()
état
« Detached »
em.merge(e)
Entity
primary key
« Managed »
Entity
primary key
« Removed »
em.remove(e)
Entity
primary key
« Managed »
Entity
primary key
« Managed »
em.find(class,pk)
transac.commit()
em.flush()
Accès à la base
de données via
JDBC / SQL
JPA – Java Persistence API ( Laurent Guérin / v 1.2 / www.laurent-guerin.fr )
45
Etat des entités
Pour suivre les évolutions des entités gérées il faut
avoir un état pour chaque instance
A chaque instance sont donc associées des
informations complémentaires qui permettront de
suivre les évolutions de l’instance
Exemple : Hibernate
Map<Object,EntityEntry> entityEntries;
Entity 1
EntityEntry
Entity 2
EntityEntry
JPA – Java Persistence API ( Laurent Guérin / v 1.2 / www.laurent-guerin.fr )
JPA - Java Persistence API
Informations sur
les entités mangées
46
23
Différents états d’une entité
Chaque entité a un état qui peut être :
New ( ou Transient ) : non géré
Managed : géré
Removed : supprimé (suppression logique)
Detached : détaché (qui n’est plus géré)
Cet état évolue en fonction des appels aux méthodes
de l’ « EntityManager »
JPA – Java Persistence API ( Laurent Guérin / v 1.2 / www.laurent-guerin.fr )
47
Différents états d’une entité
Evolution de l’état :
(doc. Open JPA)
http://openjpa.apache.org/builds/1.0.2/apache-openjpa-1.0.2/docs/manual/jpa_overview_em_lifecycle.html
JPA – Java Persistence API ( Laurent Guérin / v 1.2 / www.laurent-guerin.fr )
JPA - Java Persistence API
48
24
Différents états d’une entité
http://java.boot.by/scbcd5-guide/ch06.html
JPA – Java Persistence API ( Laurent Guérin / v 1.2 / www.laurent-guerin.fr )
49
Entity Manager
JPA - Java Persistence API
25
EntityManager
C’est l’ EntityManager qui gère toutes les
opérations de persistance des entités
PersistenceContext
Entity
primary key
« Managed »
Entity
primary key
« Managed »
Entity
primary key
« Managed »
Entity
primary key
« Removed »
JPA – Java Persistence API ( Laurent Guérin / v 1.2 / www.laurent-guerin.fr )
51
EntityManager : les principales méthodes
persist(entity)
ajout d’une nouvelle entité
merge(entity)
mise à jour d’un entité (ajout si inex.)
remove(entity)
suppression d’une entité
find(type, key)
recherche d’une entité par son id
getReference(type,key)
refresh(entity)
idem mais renvoie un « proxy »
rafraichissement (DB
lock(entity,mode)
contains(entity)
verrouillage
entité présente dans le contexte ?
flush()
force la mise à jour en base
clear()
vide le PersistenceContext
getTransaction()
close()
récupère la transaction courante
fin d’utilisation ( ne commit pas )
JPA – Java Persistence API ( Laurent Guérin / v 1.2 / www.laurent-guerin.fr )
JPA - Java Persistence API
entité)
52
26
EntityManager
Un paramètre de type « entité » est attendu par la
plupart des méthodes ( persist, merge, remove, … )
=> ce paramètre doit être une instance d’une
classe annotée « @Entity » ( avec le mapping
champs Java  colonnes de la table )
NB : cette classe doit être déclarée dans le fichier
« persistence.xml »
Si l’entité passée en paramètre ne satisfait pas ces
conditions
« IllegalArgumentException »
JPA – Java Persistence API ( Laurent Guérin / v 1.2 / www.laurent-guerin.fr )
53
Entity Manager
Les opérations de base
JPA - Java Persistence API
27
Notion de « CRUD »
CRUD :
Create
Retrieve
Update
Delete
CRUD en SQL :
C:
R:
U:
D:
Insert into … values
Select … from … where
Update … set … where
Delete from … where
Avec JPA c’est différent …
JPA – Java Persistence API ( Laurent Guérin / v 1.2 / www.laurent-guerin.fr )
55
Fonctionnement de JPA
Les méthodes de mise à jour
persist(), merge() et remove()
ne réalisent pas d'actions immédiates dans la
base de données
Ces mises à jour sont réalisées dans le
« PersistenceContext » (en mémoire)
C’est l’ EntityManager qui décide quand et comment
répercuter ces mises à jour dans la base de données,
en fonction du « FlushModeType » (AUTO ou
COMMIT)
Il n’y a pas de correspondance directe entre une
méthode JPA et un ordre SQL
JPA – Java Persistence API ( Laurent Guérin / v 1.2 / www.laurent-guerin.fr )
JPA - Java Persistence API
56
28
EntityManager : contains
public boolean contains(Object entity);
Renvoie true si le PersistenceContexte contient
la référence sur cette entité (même instance)
Le test est fait sur l’instance
et non sur la clé primaire.
=> Attention aux entités stockées par copie
(notamment par « merge »).
true em.contains( )
Entity
PK1
« Managed »
em.contains( )
false
PersistenceContext
Entity
PK1
« New »
JPA – Java Persistence API ( Laurent Guérin / v 1.2 / www.laurent-guerin.fr )
EntityManager : find
Entity
PK2
« Managed »
57
( Retrieve )
public <T> T find (Class<T> cl,
Object primKey);
Recherche une entité par sa clé primaire et la charge
dans le PersistenceContext ( si trouvée )
Un « find » se traduit par un « SELECT » SQL
L’entité chargée est créée par l’EntityManager,
son état est « Managed »
Exemple :
JPA – Java Persistence API ( Laurent Guérin / v 1.2 / www.laurent-guerin.fr )
JPA - Java Persistence API
58
29
EntityManager : find / PK Composite
Si la clé primaire est composée de plusieurs champs
(plusieurs colonnes dans la base), il faut créer une
classe dédiée qui va contenir les différentes
informations qui composent la clé
Exemple
JPA – Java Persistence API ( Laurent Guérin / v 1.2 / www.laurent-guerin.fr )
EntityManager : persist
59
( Create )
public void persist(Object entity);
Doit être utilisé dans une transaction active
( sinon TransactionRequiredException )
Comportement
Changement d’état
Si
Si
Si
Si
l’état
l’état
l’état
l’état
est
est
est
est
«
«
«
«
« Managed »
New » : passe à « Managed »
Managed » : ignoré
Removed » : passe à « Managed »
Detached » : IllegalArgumentException
Application en cascade sur toutes les relations de l’entité
(liens) ayant une annotation
cascade = { CascadeType.PERSIST, … }
( même s’il n’y a pas eu de changement d’état,
cas « Managed »
« Managed » )
JPA – Java Persistence API ( Laurent Guérin / v 1.2 / www.laurent-guerin.fr )
JPA - Java Persistence API
60
30
EntityManager : persist
Exemple :
true
false
true
SQL : Insert
Un seul Insert pour « badge 302 »
JPA – Java Persistence API ( Laurent Guérin / v 1.2 / www.laurent-guerin.fr )
61
EntityManager : persist ( instances )
Gestion des instances par « persist »
Le PersistenceContext contient une référence sur
l’ instance qui lui a été passée en paramètre.
Toute modification ultérieure de cette instance
sera donc implicitement prise en compte par le
PersistenceContext et répercutée dans la base de données
lors de l’INSERT.
L’appel a « em.contains(e) » renvoie true si e
est une référence à l’entité passée à « persist »
Si l’instance est déjà présente dans le contexte :
pas d’erreur
Si une autre instance avec la même clé primaire est déjà
présente dans le context
=> PersistanceException ( NonUniqueObjectException )
JPA – Java Persistence API ( Laurent Guérin / v 1.2 / www.laurent-guerin.fr )
JPA - Java Persistence API
62
31
EntityManager : persist ( instances )
Exemple :
persist
puis modification
SQL : Insert
Résultat :
La modification faite après « persist » est prise en compte
JPA – Java Persistence API ( Laurent Guérin / v 1.2 / www.laurent-guerin.fr )
EntityManager : remove
63
( Delete )
public void remove(Object entity);
Doit être utilisé dans une transaction active
Comportement
Changement d’état
Si
Si
Si
Si
l’état
l’état
l’état
l’état
est
est
est
est
«
«
«
«
« Removed »
New » : ignoré
Managed » : passe à « Removed »
Removed » : ignoré (état inchangé)
Detached » : IllegalArgumentException
Application en cascade sur toutes les relations de l’entité
(liens) ayant une annotation
cascade = { CascadeType.REMOVE, … }
JPA – Java Persistence API ( Laurent Guérin / v 1.2 / www.laurent-guerin.fr )
JPA - Java Persistence API
64
32
EntityManager : remove
On ne peut faire un « remove » que sur une entité
« managed » => il faut d’abord la charger dans le
« PersistenceContext »
Exemple :
SQL : Select
remove
SQL : Delete
JPA – Java Persistence API ( Laurent Guérin / v 1.2 / www.laurent-guerin.fr )
65
EntityManager : merge ( Create/Update )
public void merge(Object entity);
Fonctionnement par copie
Doit être utilisé dans une transaction active
Comportement
Changement d’état
Si
Si
Si
Si
l’état
l’état
l’état
l’état
est
est
est
est
«
«
«
«
« Managed »
New » : création d’une nouvelle entité et copie
Detached » : copie dans l’entité existante
Managed » : ignoré
Removed » : IllegalArgumentException
Application en cascade sur toutes les relations de l’entité
(liens) ayant une annotation
cascade = { CascadeType.MERGE, … }
JPA – Java Persistence API ( Laurent Guérin / v 1.2 / www.laurent-guerin.fr )
JPA - Java Persistence API
66
33
EntityManager : merge
« Merge » = « Fusion » de 2 entités
C’est-à-dire recopie d’une instance dans une autre
L’Entity Manager a besoin d’une entité cible
=> si elle n’est pas déjà dans le PersistenceContext
une instance est créée
copie
Entity
PK1
« New »
PersistenceContext
Entity
PK1
« Managed »
false
em.contains( )
Entity
PK2
« Managed »
Entity
PK3
« Managed »
em.contains( ) true
JPA – Java Persistence API ( Laurent Guérin / v 1.2 / www.laurent-guerin.fr )
67
EntityManager : merge ( instances )
Gestion des instances par « merge »
L'entité passée en paramètre est recopiée dans une autre
instance présente dans le contexte de persistance.
Si l'entité n'existe pas dans le contexte :
elle est chargée à partir de la base de données
ou une nouvelle instance est créée
Il y a donc 2 instances distinctes
« em.contains(e) » renvoie donc false
( « e » fait référence à une entité différente de celle
stockée dans le contexte )
Les modifications ultérieures sont sans effet sur l’entité du
contexte de persistance.
JPA – Java Persistence API ( Laurent Guérin / v 1.2 / www.laurent-guerin.fr )
JPA - Java Persistence API
68
34
EntityManager : merge ( instances )
Exemple :
PersistenceContext
merge(e)
1
Entity
PK1
« New »
4
copie
tx.commit()
2 recherche
Inexistant !
Entity
PK1
« Managed »
PK1
3
5
new
6
NB : Attention à travailler sur la bonne instance ( « managed » ou non )
JPA – Java Persistence API ( Laurent Guérin / v 1.2 / www.laurent-guerin.fr )
69
EntityManager : merge ( instances )
Exemples :
Sans récupération de l’entité renvoyée
pas de visibilité sur l’instance « Managed »
Inutile de modifier l’instance « badge »
pour une modification en base car ce n’est pas
celle qui est gérée dans le PersistenceContext
Avec récupération de l’entité renvoyée
possibilité de travailler sur l’instance
« Managed »
Après « commit » on aura 999 dans
la base de données
JPA – Java Persistence API ( Laurent Guérin / v 1.2 / www.laurent-guerin.fr )
JPA - Java Persistence API
70
35
EntityManager : refresh
public void refresh (entity);
S’assure que les informations de l’entité sont bien
synchronisées avec la base de données
Comportement
Pas de changement d’état ( reste à « Managed » )
Si
Si
Si
Si
l’état
l’état
l’état
l’état
est
est
est
est
«
«
«
«
New » : ignoré
Managed » : rafraichi à partir de la base
Removed » : ignoré
Detached » : IllegalArgumentException
Application en cascade sur toutes les relations de l’entité
(liens) ayant une annotation
cascade = { CascadeType.REFRESH, … }
JPA – Java Persistence API ( Laurent Guérin / v 1.2 / www.laurent-guerin.fr )
71
EntityManager : refresh
Exemple
SQL : Select
SQL : Select
« refresh » recopie les données de la base
dans l’instance et donc annule toutes les modifications
non commitées
JPA – Java Persistence API ( Laurent Guérin / v 1.2 / www.laurent-guerin.fr )
JPA - Java Persistence API
72
36
EntityManager : et l’Update ?
Il n’y a pas d’ Update explicite en JPA
Le commit suffit pour répercuter tous les
changements du « PersistenceContext » dans la base
de données
Exemple :
JPA – Java Persistence API ( Laurent Guérin / v 1.2 / www.laurent-guerin.fr )
73
EntityManager : clear / detach / close
Méthode clear()
Pour détacher toutes les entités gérées par le contexte
Toutes les modifications apportées aux entités du contexte
sont perdues
Méthode detach(entity)
Idem pour une entité spécifique
JPA 2.0 et +
L’utilisation
des méthodes
« clear » et « detach »
est généralement
déconseillée
( « anti-patterns » )
Méthode close()
Ferme l’EntityManager et libère les ressources associées
N’a pas d’effet sur la base de données
(pas de mise à jour): pas de « flush », pas de « commit »
JPA – Java Persistence API ( Laurent Guérin / v 1.2 / www.laurent-guerin.fr )
JPA - Java Persistence API
74
37
EntityManager : flush
Exemple : em.flush();
Permet de forcer les mises à jour dans la base de données
Doit être appelé dans une transaction
N’est pas un « commit », ne fait que forcer l’exécution des
requêtes SQL en attente
Les effets du « flush » sont annulés en cas de « rollback »
Comportement variable selon les implémentations de JPA
Conséquences possibles d’un « flush » :
Attribution d’une clé auto-générée (incrémentation du compteur
dans la base)
Déclenchement des « triggers »
JPA – Java Persistence API ( Laurent Guérin / v 1.2 / www.laurent-guerin.fr )
75
Gestion des transaction
JPA - Java Persistence API
38
Rappel sur les transactions
Une transaction est un regroupement d’instructions
SQL effectuant un traitement fonctionnel atomique
Exemple : opération débit/crédit
Une transaction doit être Atomique, Cohérente,
Isolée et Durable (ACID)
Atomique : indivisible, tout ou rien
Cohérente : le contenu final de la base de données doit
être cohérent
Isolée : quand 2 transactions sont exécutées
simultanément elles ne doivent pas interférer
Durable : le résultat final d’une transaction validé (état
cohérent) est conservé définitivement, même en cas
d’incident
Atomicity, Consistency, Isolation, Durability
JPA – Java Persistence API ( Laurent Guérin / v 1.2 / www.laurent-guerin.fr )
77
L’objet Transaction
Dans JPA la gestion des transactions de fait via
l’interface « EntityTransaction »
Une instance de transaction est récupérée
à partir de l’ EntityManager
EntityTransaction transaction = em.getTransaction();
JPA – Java Persistence API ( Laurent Guérin / v 1.2 / www.laurent-guerin.fr )
JPA - Java Persistence API
78
39
Délimiter une transaction
Début
em.getTransaction().begin();
Fin
em.getTransaction().commit();
em.getTransaction().rollback();
Exemple :
JPA – Java Persistence API ( Laurent Guérin / v 1.2 / www.laurent-guerin.fr )
79
Etat d’une transaction
Comment savoir si une transaction est déjà active ?
em.getTransaction().isActive();
isActive()
false
begin()
isActive()
true
commit() / rollback()
isActive()
false
JPA – Java Persistence API ( Laurent Guérin / v 1.2 / www.laurent-guerin.fr )
JPA - Java Persistence API
80
40
Cas d’erreur
Si la transaction est déjà active
em.getTransaction().begin();
java.lang.IllegalStateException
Si la transaction n’est pas active
em.getTransaction().commit(); ( ou rollback )
java.lang.IllegalStateException
JPA – Java Persistence API ( Laurent Guérin / v 1.2 / www.laurent-guerin.fr )
81
Les requêtes
JPQL, SQL et Criteria API
JPA - Java Persistence API
41
Requêtes : les différents langages/API
Un des principaux objectifs de JPA est de ne plus
utiliser SQL pour les accès à la base de données
JPA fournit donc un langage de requêtes
indépendant du SQL de la base de données :
Java Persistence Query Language ( JP QL )
JPA fournit également une API Java permettant de
construire des requêtes dynamiquement par des
appels de méthodes Java : la « Criteria API »
Enfin, des requêtes exprimées en SQL natif sont
parfois nécessaires : JPA permet d’appeler des
requêtes écrites en SQL natif
JPA – Java Persistence API ( Laurent Guérin / v 1.2 / www.laurent-guerin.fr )
83
JP QL
JP QL est une révision (extension et amélioration)
de EJB QL (langage de requête pour les EJB)
La syntaxe reste très proche du SQL
( SELECT, FROM, WHERE, ... )
Principale différence :
en JP QL on ne fait pas un SELECT sur une TABLE,
mais sur une CLASSE JAVA (un type d’entité)
Exemples :
SELECT e.name FROM Employee e
Classe :
Employee.java
Employee.class
SELECT e FROM Employee e
WHERE e.department.name = ‘AB’
AND
e.address.state IN ( ‘NY’, ‘CA’ )
JPA – Java Persistence API ( Laurent Guérin / v 1.2 / www.laurent-guerin.fr )
JPA - Java Persistence API
84
42
JP QL – Paramètres
Les paramètres des requêtes JP QL peuvent être
représentés par un nom symbolique précédé de ‘:’
:nom
SELECT b FROM Badge b
WHERE b.badgeNumber >= :min
AND
b.badgeNumber <= :max
Ou par un numéro précédé de ‘?’
?indice ( numéros quelconques : ?11 ?32 … )
SELECT b FROM Badge b
WHERE b.badgeNumber >= ?1
AND
b.badgeNumber <= ?2
JPA – Java Persistence API ( Laurent Guérin / v 1.2 / www.laurent-guerin.fr )
85
JP QL – Requête dans le code Java
Requête JP QL sans paramètre
final String QUERY = "SELECT b.badgeNumber FROM Badge b " ;
Query query = em.createQuery( QUERY ) ;
//--- Execute query
System.out.println("execute query ...");
List<Integer> list = query.getResultList() ;
0 .. N instances
de type Integer
System.out.println("Number of badges : " + list.size() );
for ( Integer i : list ) {
System.out.println(" . badge number : " + i );
}
final String QUERY = "SELECT b FROM Badge b" ;
...
List<Badge> list = query.getResultList() ;
..
0 .. N instances
de type Badge
instances « managed » dans le « PersistenceContext »
JPA – Java Persistence API ( Laurent Guérin / v 1.2 / www.laurent-guerin.fr )
JPA - Java Persistence API
86
43
JP QL – Requête dans le code Java
Requête JP QL avec paramètres
final String QUERY = "SELECT b FROM Badge b "
+ "WHERE b.badgeNumber >= :min AND b.badgeNumber <= :max
Query query = em.createQuery( QUERY ) ;
//---- Set parameters
query.setParameter("min", 100);
query.setParameter("max", 310);
" ;
Paramètres
nommés
//--- Execute query
List<Badge> list = query.getResultList();
final String QUERY = "SELECT b FROM Badge b "
+ "WHERE b.badgeNumber >= ?1 AND b.badgeNumber <= ?2" ;
Query query = em.createQuery( QUERY ) ;
Paramètres
numérotés
//---- Set parameters
query.setParameter( 1, 100);
query.setParameter( 2, 310);
...
JPA – Java Persistence API ( Laurent Guérin / v 1.2 / www.laurent-guerin.fr )
87
JP QL – Update & Delete
JP QL permet de faire des mise à jour (utile
notamment pour appliquer une mise à jour sur
plusieurs « records » en une seule requête)
String QUERY = "UPDATE Badge b SET b.authorizationLevel = 123 "
+ " WHERE b.badgeNumber > 300 " ;
String QUERY = "DELETE Badge b WHERE b.badgeNumber > 400" ;
em.getTransaction().begin();
int r = query.executeUpdate();
em.getTransaction().commit();
// retour : Nb de records affectés
Update & Delete uniquement ( pas d’insert )
Utilisable sur un seul type d’entité à la fois
Les entités stockées dans le « PersistenceContext » ne sont pas
mises à jour => risque d’incohérence
A exécuter dans une transaction dédiée ou au début d’une transaction
JPA – Java Persistence API ( Laurent Guérin / v 1.2 / www.laurent-guerin.fr )
JPA - Java Persistence API
88
44
JP QL – « @NamedQuery »
Définition d’une requête nommée :
Définition par
annotations
@Entity(name = "EMPLOYEE")
dans une entité
@NamedQueries({
@NamedQuery( name = "Employee.findAll",
query = "SELECT EMP FROM EMPLOYEE AS EMP" )
})
public class Employee implements Serializable {
@Id
@Column(name = "EMP_ID", nullable = false)
private Long id;
@Column(name = "EMP_NAME", nullable = false, length = 100)
private String name;
// .. ..
}
Utilisation :
public List findAllEmployees(){
Query query = entityManager.createNamedQuery( "Employee.findAll" );
List employees = query.getResultList();
return (employees);
}
JPA – Java Persistence API ( Laurent Guérin / v 1.2 / www.laurent-guerin.fr )
89
SQL natif
Bien que JP QL soit le langage recommandé pour
exprimer des requêtes, dans certains cas des
requêtes écrites en SQL natif (avec éventuellement
des spécificités liées à la base de données) peuvent
s’avérer nécessaires
Les requêtes SQL natives restent gérées par
l’ EntityManager ce qui permet de profiter du
mapping des entités
Le « ResultSet » de la requête native peut renvoyer
des entités JPA ( @Entity )
JPA – Java Persistence API ( Laurent Guérin / v 1.2 / www.laurent-guerin.fr )
JPA - Java Persistence API
90
45
SQL natif – Mapping
Mapping sur Badge
doit être une entité
Mapping sur une entité :
connue de JPA
(@Entity)
final String QUERY = "SELECT * FROM BADGE" ;
Query query = em.createNativeQuery( QUERY, Badge.class) ;
@SuppressWarnings("unchecked")
List<Badge> list = query.getResultList();
instances « managed » dans le « PersistenceContext »
1 seule colonne ( int )
Mapping sur un type primitif :
final String QUERY = "SELECT BADGE_NUMBER FROM BADGE" ;
Query query = em.createNativeQuery( QUERY ) ;
Rien (pas de type)
@SuppressWarnings("unchecked")
List<Integer> list = query.getResultList();
Type compatible avec le ResultSet
JPA – Java Persistence API ( Laurent Guérin / v 1.2 / www.laurent-guerin.fr )
91
SQL natif – Mapping
1 seule colonne ( int )
Incompatible !
Mapping sur
une entité
(@Entity)
final String QUERY = "SELECT ID FROM PERSON" ;
Query query = em.createNativeQuery( QUERY, Person.class) ;
List<Person> list = query.getResultList();
Dans les anciennes versions de JPA :
Liste d’instances contenant toutes les informations
de l’entité (pas uniquement la colonne sélectionnée)
Les entités sont intégralement valorisées
Dans les versions récentes de JPA :
Erreur : « SQLGrammarException »
Cause : « Column "XXXX" not found »
final String QUERY = "SELECT FIRST_NAME, LAST_NAME, ID FROM PERSON";
Query query = em.createNativeQuery( QUERY, Person.class) ;
List<Person> list = query.getResultList();
OK, toutes les colonnes sont présentes (peu importe l’ordre)
JPA – Java Persistence API ( Laurent Guérin / v 1.2 / www.laurent-guerin.fr )
JPA - Java Persistence API
92
46
SQL natif – Paramètres
Il est possible d’utiliser…
Des paramètres ‘?’ comme en JDBC :
final String QUERY = "SELECT * FROM PERSON "
"WHERE ID >= ? AND ID <= ? " ;
query.setParameter(1, 300);
query.setParameter(2, 310);
Des paramètre numérotés
Une seule
et même
requête
JDBC :
final String QUERY = "SELECT * FROM PERSON "
"WHERE ID >= ?11 AND ID <= ?22 ";
query.setParameter(11, 300);
query.setParameter(22, 310);
Des paramètres nommés
final String QUERY = "SELECT * FROM PERSON "
"WHERE ID >= :min AND ID <= :max ";
query.setParameter("min", 300);
query.setParameter("max", 310);
JPA – Java Persistence API ( Laurent Guérin / v 1.2 / www.laurent-guerin.fr )
93
SQL natif – « @NamedNativeQuery »
@Entity
@Table(name="PERSON" )
@NamedNativeQueries ( {
@NamedNativeQuery ( name="Person.maxId",
query="SELECT MAX(ID) FROM PERSON" ),
@NamedNativeQuery ( name="Person.selection",
query="SELECT * FROM PERSON WHERE ID >= :min AND ID <= :max",
resultClass=PersonEntity.class )
})
public class PersonEntity implements Serializable { .... }
Query query = em.createNamedQuery("Person.maxId") ;
Integer maxId = (Integer) query.getSingleResult();
Query query = em.createNamedQuery("Person.selection") ;
query.setParameter("min", 2);
query.setParameter("max", 3);
@SuppressWarnings("unchecked")
// Récupération conforme à « resultClass=PersonEntity.class »
List<PersonEntity> list = query.getResultList();
JPA – Java Persistence API ( Laurent Guérin / v 1.2 / www.laurent-guerin.fr )
JPA - Java Persistence API
94
47
SQL natif – Mapping spécifique
Par défaut, le type renvoyé par
query.getResultList() est List<Object[]>
chaque tableau correspondant à un « record »
composé de « N colonnes »
Query query = em.createNativeQuery( "SELECT * FROM PERSON " );
@SuppressWarnings("unchecked")
List<Object[]> list = query.getResultList();
System.out.println("Result list size = " + list.size());
for ( Object[] record : list ) {
System.out.println(" . " + record[0] + " " + record[1] );
}
Pas très pratique :-(
« @SqlResultSetMapping » permet
de « mapper » ce résultat brut plus facilement
JPA – Java Persistence API ( Laurent Guérin / v 1.2 / www.laurent-guerin.fr )
95
@SqlResultSetMapping / Colonnes
Utilisation avec une requête basée sur une jointure
JPA – Java Persistence API ( Laurent Guérin / v 1.2 / www.laurent-guerin.fr )
JPA - Java Persistence API
96
48
@SqlResultSetMapping / Colonnes
Définition du mapping :
Résultat :
3 colonnes
JPA utilise les noms de colonnes pour
faire le mapping => pas de noms de
colonnes identiques, utiliser les « alias »
dans la requête SQL si nécessaire
Exécution de la requête native :
On récupère une
liste de colonnes
Ligne
Colonne
JPA – Java Persistence API ( Laurent Guérin / v 1.2 / www.laurent-guerin.fr )
List<Object[]>
97
@SqlResultSetMapping / Entités
Utilisation avec une requête basée sur une jointure
JPA – Java Persistence API ( Laurent Guérin / v 1.2 / www.laurent-guerin.fr )
JPA - Java Persistence API
98
49
@SqlResultSetMapping / Entités
Définition du mapping :
Résultat :
2 entités
JPA utilise les noms de colonnes pour
faire le mapping => pas de noms de
colonnes identiques, utiliser les « alias »
dans la requête SQL si nécessaire
JPA – Java Persistence API ( Laurent Guérin / v 1.2 / www.laurent-guerin.fr )
99
@SqlResultSetMapping / Entités
Exécution de la requête native :
NB : on récupère une liste de tableaux d’objets :
list
array[0]
array[1]
ProfessorEntity
DepartmentEntity
ProfessorEntity
DepartmentEntity
ProfessorEntity
DepartmentEntity
JPA – Java Persistence API ( Laurent Guérin / v 1.2 / www.laurent-guerin.fr )
JPA - Java Persistence API
Résultat :
2 entités
=> 2 éléments
100
50
@SqlResultSetMapping / POJO (DTO)
JPA 2.1
« POJO » avec un constructeur
comportant toutes les colonnes
Définition du mapping dans
une classe « @Entity »
Classe Java
Nom des colonnes SQL
dans l’ordre du constructeur
Utilisation
JPA – Java Persistence API ( Laurent Guérin / v 1.2 / www.laurent-guerin.fr )
101
SQL natif – Mises à jour
Utilisation possible de : Update, Delete, Insert
final String QUERY = "DELETE FROM BADGE WHERE BADGE_NUMBER > 400" ;
final String QUERY =
"INSERT INTO BADGE (BADGE_NUMBER, AUTHORIZATION_LEVEL) "
+ "VALUES (801,3 ) " ;
Query query = em.createNativeQuery( QUERY ) ;
em.getTransaction().begin();
//--- Execute query
int r = query.executeUpdate();
em.getTransaction().commit();
Utilisation généralement déconseillée car ce type de requête
peut provoquer des écarts entre les entités stockées dans le
« PersistenceContext » et la base de données
=> à utiliser avec précaution
JPA – Java Persistence API ( Laurent Guérin / v 1.2 / www.laurent-guerin.fr )
JPA - Java Persistence API
102
51
Criteria API
Criteria API est une alternative à JP QL
Cette API permet de construire des critères de
requêtes à l’aide d’objets Java
Les objectifs de Criteria API :
s’affranchir des chaines de caractères qui définissent les
requêtes en JP QL (pas de contrôle à la compilation Java,
erreurs de syntaxe décelées à l’exécution )
apporter un contrôle de type ( « type-safe » )
Criteria API repose essentiellement sur 2 objets :
CriteriaBuilder
CriteriaQuery
JPA – Java Persistence API ( Laurent Guérin / v 1.2 / www.laurent-guerin.fr )
103
Criteria API - Exemples
Avec JP QL
String QUERY = "SELECT b FROM Badge b where badgeNumber = 305" ;
Query query = em.createQuery( QUERY ) ;
List<Badge> list = query.getResultList();
Avec Criteria API
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<Badge> c = cb.createQuery(Badge.class);
//--- Criteria definition
Root<Badge> badge = c.from(Badge.class);
c.select(badge)
.where( cb.equal( badge.get("badgeNumber"), 305 ) );
Query query = em.createQuery( c ) ;
List<Badge> list = query.getResultList();
JPA – Java Persistence API ( Laurent Guérin / v 1.2 / www.laurent-guerin.fr )
JPA - Java Persistence API
104
52
Criteria API
Criteria
API
Interfaces
Très riche
JPA – Java Persistence API ( Laurent Guérin / v 1.2 / www.laurent-guerin.fr )
105
Criteria API - Exemples
String param = "Archive";
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<Long> query = cb.createQuery(Long.class);
Root<Music> music = query.from(Music.class);
query.select(cb.count(music));
query.where(cb.equal(music.<String>get("artisteName"),
cb.parameter(String.class,"artisteNameParam")));
TypedQuery<Long> tq = em.createQuery(query);
tq.setParameter("artisteNameParam", param);
String param = "Arc%";
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<String> query = cb.createQuery(String.class);
Root<Music> music = query.from(Music.class);
query.select(music.<String>get("artisteName"));
query.distinct(true);
query.where(cb.like(music.<String>get("artisteName"),
cb.parameter(String.class, "param")));
TypedQuery<String> tq = em.createQuery(query);
tq.setParameter("param", param);
JPA – Java Persistence API ( Laurent Guérin / v 1.2 / www.laurent-guerin.fr )
JPA - Java Persistence API
106
53
Objet « Query » – Compléments
Récupérer un seul résultat (et non une liste)
Query query = em.createNativeQuery("SELECT COUNT(*) FROM PERSON");
BigInteger count = (BigInteger) query.getSingleResult();
// type “Long” si requête JPQL
Limiter le nombre d’occurrences récupérées
Query query = em.createQuery( "SELECT p FROM Person p" );
query.setMaxResults(10); // Au plus 10 occurrences
Définir la première occurrence à récupérer
Query query = em.createQuery( "SELECT p FROM Person p" );
// “Offset” : Premier = 0, Deuxième = 1, etc
query.setFirstResult(50);
JPA – Java Persistence API ( Laurent Guérin / v 1.2 / www.laurent-guerin.fr )
107
Objet « Query » – Pagination
La pagination peut être gérée simplement en
combinant l’utilisation de setMaxResults
et de setFirstResult
Query query = em.createNativeQuery(
"SELECT * FROM PERSON" );
query.setMaxResults(pageSize);
page
int offset = ( pageNumber - 1 ) * pageSize ;
// 0, 20, 40, 60, ...
query.setFirstResult(offset);
@SuppressWarnings("unchecked")
List<PersonEntity> list = query.getResultList();
JPA va construire des requêtes SQL adaptées à la base cible.
Utilisation de « LIMIT », « OFFSET », « rownum », etc…
Exemples :
base H2 : " SELECT * FROM PERSON limit ? offset ? "
base Oracle : SELECT * FROM (SELECT /*+ FIRST_ROWS */ p.*, ROWNUM rnum
FROM (SELECT ... FROM PERSON) p WHERE ROWNUM <= ? ) WHERE rnum > ?
JPA – Java Persistence API ( Laurent Guérin / v 1.2 / www.laurent-guerin.fr )
JPA - Java Persistence API
108
54
Cache de « 2ème niveau »
Le cache de 2ème niveau
« Shared Cache » ou « Second Level Cache »
Cache géré au niveau « EntityManagerFactory »
Cache partagé par tous les « EntityManager »
Évite des accès à la base
=> améliore les performances
JPA – Java Persistence API ( Laurent Guérin / v 1.2 / www.laurent-guerin.fr )
JPA - Java Persistence API
110
55
Gestion du cache ( 4 méthodes )
Vérifier si une entité est dans
EntityManager em = ...;
Cache cache = em.getEntityManagerFactory().getCache();
String personPK = ...;
if ( cache.contains(Person.class, personPK) ) {
// the data is cached
} else {
// the data is NOT cached
}
le cache
Retirer une/des entité(s)
EntityManager em = ...;
Cache cache = em.getEntityManagerFactory().getCache();
String personPK = ...;
du cache
cache.evict(Person.class, personPK); // Une instance (Prim. Key )
cache.evict(Person.class); // Toutes les instances d’une classe
cache.evictAll(); // Toutes les instances
JPA – Java Persistence API ( Laurent Guérin / v 1.2 / www.laurent-guerin.fr )
111
Configuration du cache
Les différents modes :
ALL
NONE
ENABLE_SELECTIVE
DISABLE_SELECTIVE
UNSPECIFIED
All entity data is stored in the second-level cache for this persistence
unit.
No data is cached in the persistence unit. The persistence provider must
not cache any data.
Enable caching for entities that have been explicitly set with
the @Cacheable annotation.
Enable caching for all entities except those that have been explicitly set
with the @Cacheable(false) annotation.
The caching behavior for the persistence unit is undefined. The
persistence provider's default caching behavior will be used.
persistence.xml
<persistence-unit name="examplePU" transaction-type="JTA">
<provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
<jta-data-source>jdbc/__default</jta-data-source>
<shared-cache-mode>DISABLE_SELECTIVE</shared-cache-mode>
</persistence-unit>
Dans le code
Properties prop = new Properties();
prop.add("javax.persistence.sharedCache.mode", "ENABLE_SELECTIVE" ));
EntityManagerFactor emf =
Persistence.createEntityManagerFactory( "examplePU", prop );
JPA – Java Persistence API ( Laurent Guérin / v 1.2 / www.laurent-guerin.fr )
JPA - Java Persistence API
112
56
FIN
JPA - Java Persistence API
57
Téléchargement