Vous êtes sur la page 1sur 14

Facult I&C, Claude Petitpierre 1

J PA: J ava Persistence API


J avabeans synchronisables
avec la base de donnes
Autres noms: Hibernate, EJ B3
Facult I&C, Claude Petitpierre 2
Objet J PA
@Entity
public class Vin implements java.io.Serializable {
@Id
@GeneratedValue(strategy =GenerationType.IDENTITY)
private Long id =null;
private String nomVin;
public Long getId() { // getters setters, gnrs par Eclipse
return id;
}
public void setId(Long id) {
this.id =id;
}
public String getNomVin() {
return nomVin;
}
}
Facult I&C, Claude Petitpierre 3
Objet J PA avec attributs non persistants
@Entity
public class Vin implements java.io.Serializable {
@Id
@GeneratedValue(strategy =GenerationType.IDENTITY)
private Long id =null;
private String nomVin;
transient private String flag; // pas dans la BD, pas srialis
@Transient
private String caracteristique; // pas dans la BD
// getters / setters
}
// les transients ne sont utiliss que dans la JSF, pas dans la BD
Facult I&C, Claude Petitpierre 4
Importations dans un J PA
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
@Entity
public class Vin implements java.io.Serializable {
. . .
}
Facult I&C, Claude Petitpierre 5
Insrer un objet dans la base de donnes
javax.persistence.EntityManager em =ejb3_utility.Manager.open();
javax.persistence.EntityTransaction tx =em.getTransaction();
tx.begin();
Vin vin =new Vin(nomV, cepage, annee);
em.persist(vin);
tx.commit(); // or tx.rollback();
ejb3_utility.Manager.close();
Facult I&C, Claude Petitpierre 6
Manager.java est li un thread
(dtails)
private static ThreadLocal<Manager>threadManager
=new ThreadLocal<Manager>() { // nameless class
protected synchronized Manager initialValue() {
return (new Manager());
}
};
Facult I&C, Claude Petitpierre 7
Manager.java (partiel)
private EntityManager em=null;
public static EntityManager open() {
Manager manager =(Manager) threadManager.get();
if (manager.em==null) {
Manager.emf =Persistence
.createEntityManagerFactory("NomDeManager");
manager.em=Manager.emf.createEntityManager();
manager.em.setFlushMode(FlushModeType.COMMIT);
}
return manager.em;
}
Facult I&C, Claude Petitpierre 8
Cration dun projet contenant
des J PAs
Facult I&C, Claude Petitpierre 9
Projet avec objets J PA
Crer un Dynamic Web Project
Ajouter la liste de .jar dans
WebContent/WEB-INF/lib
Ajouter ejb3_utility/Manager.java dans src
Ajouter META-INF/persistence.xml dans le
rpertoire src et introduire le nom de chaque
JPA dans ce fichier
Ajouter mysql_connector.jar dans Tomcat/lib
Facult I&C, Claude Petitpierre 10
Persistence.xml (partie)
<persistence-unit name="NomDeManager">
<class>db.Vin</class>
<properties>
<property name="hibernate.dialect" value="org.hibernate.dialect.MySQLDialect"/>
<property name="hibernate.hbm2ddl.auto" value="update"/>
<property name="hibernate.connection.driver_class" value="com.mysql.jdbc.Driver"/>
<property name="hibernate.connection.username" value="username"/>
<property name="hibernate.connection.password" value="password"/>
<property name="hibernate.connection.url" value="jdbc:mysql://localhost:3306/test"/>
<property name="javax.persistence.transactionType" value="RESOURCE_LOCAL"/>
</properties>
</persistence-unit>
</persistence>
Facult I&C, Claude Petitpierre 11
Intgration d'un J PA dans un projet
Structure selon Usager.java
Introduire le J PA dans les ManagedBean, s'il est
affich dans une J SF
Introduire son package.nom dans persistence.xml
Facult I&C, Claude Petitpierre
Introduire un objet
dans la base de donnes
javax.persistence.EntityManager em =ejb3_utility.Manager.open();
javax.persistence.EntityTransaction tx =em.getTransaction();
tx.begin();
Vin vin =new Vin(nomV, cepage, annee);
em.persist(vin);
// les modifications faites ici sont aussi introduites dans la BD
tx.commit(); // or tx.rollback();
ejb3_utility.Manager.close();
// persist ajoute automatiquement un id dans le champ @Id de l'objet
Facult I&C, Claude Petitpierre
Modification dun objet dans la BD: merge()
A la fin d'une mthode, avant de retourner la page
afficher dans le navigateur, on doit naturellement
fermer la transaction.
Lorsque l'on affiche un objet sur une page, on n'est
donc plus dans la transaction
Lorsque lutilisateur demande la page de
transmettre les modifications (<form action=" ">), elle
appelle une nouvelle action
Dans cette action, il faut ouvrir une nouvelle
transaction et y rintroduire l'objet merge() pour
que les modifications soient enregistres dans la BD
Facult I&C, Claude Petitpierre
Personne
Opration merge
Personne
DB
em.persist(p)
p1 = em.merge(p)
Personne
Manager
p =new Personne()
p
p1
Premire
transaction
Deuxime
transaction
// les modifications de p1 sont transmises dans la BD
Facult I&C, Claude Petitpierre
Fonctionnement du merge
Personne
Id : 5
Personne
Id : 5
p1
p
Manager
p1 =em.merge(p)
5
p1 est une copie de p
Seules les modifications
sur p1 seront transmises
la base de donnes la
fermeture de la transaction
Facult I&C, Claude Petitpierre
Personne Personne
Opration merge
Personne
id=3
DB
Page
em.persist(p)
Page Page Page
p =em.merge(p)
Personne
id=3
p =em.merge(p)
Personne
id=3
session
A programmer
explicitement
Facult I&C, Claude Petitpierre
merge d'un objet dj dans la transaction
Personne
Id : 5
p1
Manager
p3 =em.merge(p1)
5
On suppose que p1 et p2 ont t crs par un moyen quelconque, par exemple
en introduisant directement 5 dans l'id
Si l'id est dj rfrenc, le contenu du nouvel objet est copi dans l'objet
rfrenc et l'objet rfrenc est retourn
Personne
Id : 5
p3
mmorisation
Facult I&C, Claude Petitpierre
merge d'un objet dj dans la transaction
Personne
Id : 5
Personne
Id : 5
p2
p1
Manager
p3 =em.merge(p1)
5
On suppose que p1 et p2 ont t crs par un moyen quelconque, par exemple
en introduisant directement 5 dans l' id. Le premier merge introduit p3 dans la
transaction
Comme l' id de p2 est dj rfrenc, le deuxime merge copie le contenu du
nouvel objet dans l'objet p3 puis la rfrence de cet objet est retourne dans p4
p4 =em.merge(p2)
Personne
Id : 5
p3
mmorisation
copie du contenu
p4
Facult I&C, Claude Petitpierre
Indirection dans la session
(p reste dans la session)
Personne
Business
Personne p;
public void action() {
. . .
p =em.merge(p);
. . .
}
session
Facult I&C, Claude Petitpierre
Relations entre J PAs
Facult I&C, Claude Petitpierre 21
Relations entre J PA 1:1
Marchand
nomMarchand
vin
Vin
nomVin
cepage
annee
marchand
1 1
@OneToOne
private Marchand marchand;
Dans Marchand
(il faut choisir un
ct pour mappedBy)
Dans Vin
@OneToOne(mappedBy="marchand")
private Vin vin;
// Getters setters pour les deux champs
Facult I&C, Claude Petitpierre 22
Relations entre J PA 1:N
Marchand
nomMarchand
vins
Vin
nomVin
cepage
annee
marchand
1 N
@ManyToOne
private Marchand marchand;
Dans Marchand
Dans Vin
@OneToMany(mappedBy="marchand")
private Collection<Vin>vins;
// Getters setters pour la collection et pour le champ marchand
Facult I&C, Claude Petitpierre 23
Relations entre J PA N:M
Marchand
nomMarchand
vins
Vin
nomVin
cepage
annee
marchands
N M
@ManyToMany(mappedBy="vins")
private Collection marchands;
Dans Marchand
Dans Vin
@ManyToMany
private Collection<Vin>vins;
// Getters setters pour les deux collections
Facult I&C, Claude Petitpierre 24
Relations entre J PA N:M, cascade
@ManyToMany(mappedBy="vins")
private Collection marchands =new ArrayList<Marchand>();
Dans Marchand
Dans Vin
@ManyToMany (cascade = CascadeType.ALL)
private Collection<Vin>vins =new ArrayList<Vin>();
// Persistence et remove cascads
Facult I&C, Claude Petitpierre 25
Insertion de J PAs dans les relations
Facult I&C, Claude Petitpierre
Relation dans la base de donnes et
dans les objets
C'est la responsabilit du dveloppeur d'introduire les relations
dans les deux sens entre les objets.
Pour qu'elles soient introduites dans la base de donnes, il faut
faire cette opration dans une transaction du manager. C'est--
dire que le principal soit attach (voir plus loin) et l'objet ajout
pas libre.
De plus il faut introduire au moins l'lment du ct qui n'a pas
l'indication mappedBy.
Facult I&C, Claude Petitpierre 27
Relations entre J PA 1:1
@OneToOne
private Marchand marchand;
@OneToOne(mappedBy="marchand")
private Vin vin;
tx.begin();
marchand =em.merge(marchand);
em.persist(v);
marchand.setVin(v);
tx.commit();
tx.begin();
vin =em.merge(vin);
em.persist(m);
vin.setMarchand(m);
tx.commit();
// ncessaire et suffisant pour
// introduire la relation dans la BD
Facult I&C, Claude Petitpierre 28
Relations entre J PA 1:N
@ManyToOne
private Marchand marchand;
@OneToMany(mappedBy="marchand")
private Collection<Vin>vins;
tx.begin();
marchand =em.merge(marchand);
em.persist(v);
marchand.vins.add(v);
tx.commit();
tx.begin();
vin =em.merge(vin);
em.persist(m);
vin.setMarchand(m);
tx.commit();
// ncessaire et suffisant pour
// introduire la relation dans la BD
Facult I&C, Claude Petitpierre 29
Relations entre J PA N:M
@ManyToMany(mappedBy="vins")
private Collection marchands;
@ManyToMany
private Collection<Vin>vins;
tx.begin();
marchand =em.merge(marchand);
em.persist(v);
marchand.vins.add(v);
tx.commit();
// les instructions d'un seul ct suffisent
// pour entrer la relation dans la BD
tx.begin();
vin =em.merge(vin);
em.persist(m);
vin.marchands.add(m);
tx.commit();
Facult I&C, Claude Petitpierre
Parcourir des lments d'une relation x:N
public class Marchand {
@OneToMany(mappedBy="marchand")
private Collection<Vin>vins;
public void setVins() {}
public Collection<Vin>getVins() {}
}
// . . . transaction . . .
marchand =em.merge(marchand);
for (Vin v: marchand.getVins()) { // relation
System.out.println(v.getNom());
}
// Les vins sont automatiquement "mergs" quand
// on parcourt la collection
Facult I&C, Claude Petitpierre
merge dans les relations
Cours
id=3
Etudiant
id=8
Etudiant
id=4
Etudiant
id=7
c
Manager
id: 3, 8, 4, 7
c1 =em.merge(c)
Cours
id=3
c1
for (Vin v: marchand.getVins()) {
System.out.println(v.getNom());
} // mergs automatiquement
Cours
id=3
c1
Etudiant
id=8
Etudiant
id=4
Etudiant
id=7
pas de copie
BD
extraction
Facult I&C, Claude Petitpierre
merge dans les relations
Cours
id=3
Etudiant
id=8
Etudiant
id=4
Etudiant
id=7
c
Manager
3, 8, 4, 7
c1 =em.merge(c)
Cours
id=3
c1
for (Vin v: marchand.getVins()) {
System.out.println(v.getNom());
}// le 4 est repris car il est dj merg
Cours
id=3
c1
Etudiant
id=8
Etudiant
id=7
et =em.merge(et)
Etudiant
id=4
et
Les modifications sur
les objets bleus sont
rpercutes dans la BD
et
Facult I&C, Claude Petitpierre
Rattachement la base de donnes
Comme dcrit prcdemment, les objets J PA sont crs
indpendamment de la base de donnes et leur synchroni-
sation avec celle-ci est faite de faon explicite.
Un objet peut donc tre libre (pas d'ID), attach (un ID et
dans une transaction) ou dtach (a conserv son ID, mais
n'est pas li une transaction).
Un objet mmoris dans la session HTTP peut garder son ID
d'une page l'autre. Pour le rintgrer dans une transaction,
il faut utiliser merge, comme expliqu sur les pages qui
prcdent.
De mme pour un objet qui serait lu par une query, il obtient
un ID, mais il n'est pas attach la transaction.
Facult I&C, Claude Petitpierre
Elements
attachs
em = Manager.open();
client = new Client("Hans");
// libre
tx.begin();
em.persist(p);
// attach
tx.commit();
Manager.close();
// dtach, son id reste initialis
client.setId(0);
// libre
client = (Client) result.getSingleResult();
// dtach
Facult I&C, Claude Petitpierre
merge()
Client client =(Client)result.getSingleResult();
// dtach, son id est initialis
tx.begin();
client2 =em.merge(client);
// attach, les modifications seront enregistres au commit
tx.commit();
// em.merge() retourne une copie intgre dans la transaction
// Donc attention, si client est enregistr dans la session
// HTTP, il faudra le r-enregistrer dans cette session !
Facult I&C, Claude Petitpierre
Mises jour
Quand un objet attach est mis jour, ses modifica-
tions sont suivies dans le manager et lors du commit,
elles sont transmise dans la base de donnes.
Il en est de mme avec les relations.
Pour vrifier que le systme ragit selon nos plans, il
suffit d'afficher les tables en utilisant le moniteur de
MySQL
Facult I&C, Claude Petitpierre 37
J QL
Adaptation de SQL aux J PA
Facult I&C, Claude Petitpierre 38
Utilisation de J QL
Query result =em.createQuery("SELECT v FROM Vin v");
vin =(Vin)result.getSingleResult(); // une seule ligne,
// une exception est jete si la commande
// en dfinit plusieurs
vins =(ArrayList<Vin>) result.getResultList(); // plusieurs lignes
// le find est automatiquement attach au manager
Facult I&C, Claude Petitpierre
Elimination d'un lment
Query result =em.createQuery(
"SELECT v FROM Vin v WHERE v.nomVin="Bourgogne"
);
vin =(Vin)result.getSingleResult();
. . .
em.remove(vin);
Facult I&C, Claude Petitpierre
J QL avec relations
40
Relation 1:1
SELECT m FROM Marchand m
WHERE m.vin.nom='Epesse
(m.vin est un attribut)
Relation 1:N, N:N
SELECT m FROM Marchand m, IN(m.sesVins) v
WHERE v.nom='Epesse'
(m.sesVins est une collection)
Facult I&C, Claude Petitpierre
Introduire un lment dans une relation
Query result =em.createQuery(
"SELECT c FROM Client c
WHERE c.nom=' "+nomClient+" ' ");
Client client =(Client) result.getSingleResult();
tx.begin();
client.getPanier().add(p);
tx.commit(); // or tx.rollback();
Facult I&C, Claude Petitpierre
Lazy loading (1)
42
Lorsque le manager charge une relation qui ne ncessite quun attribut
(1:1, 1:N), il charge directement lunique lment de la relation.
Lorsquil doit charger une liste (N:M, N:1), il ne charge les lments que
lorsquils sont accds. Ainsi, dans lexemple ci-desous, les lments ne
sont plus accessibles, car la transaction est ferme avant daccder aux
lments (on suppose que client a une relation 1:N avec produits):
Client client = (Client)result.getSingleResult();
tx.begin();
client2 = em.merge(client);
tx.commit();
for (Produit p: client2.listeProduits) {
print(p); // ne sont plus accessibles
}
Facult I&C, Claude Petitpierre
Lazy loading (2)
43
Pour forcer le chargement pendant que la liste est dans la transaction, il faut
y accder, par exemple en appelant la fonction size():
Client client = (Client)result.getSingleResult();
tx.begin();
Client client2 = em.merge(client);
client2.size(); // juste pour forcer le chargement
tx.commit();
for (Produit p: client2.listeProduits) {
print(p); // disponibles
}
// Note: on pourrait aussi spcifier que le chargement soit fait doffice
// (eager loading) dans les paramtres du JPA (voir la doc spcialise).
Facult I&C, Claude Petitpierre
Transactions gres par version
Soit la squence d'vnements:
On cre ou lit un J PA depuis une page
Dans un page suivante, on merge ce J PA pour le modifier
La modification est faite correctement
On relit une J PA depuis une page
Un autre utilisateur lit la mme J PA
Il la modifie (La modification est faite correctement)
Le premier utilisateur clique sur sa page
Il modifie le J PA
La premire modification est oublie.
Le champ de version va permettre de signaler ce problme.
Facult I&C, Claude Petitpierre
Transactions gres par version
@Version
private int uneVersion;
// getters / setters
Facult I&C, Claude Petitpierre
Transactions gres par version
public void enregistrer() { // cration d'un JPA
this.id =null;
try {
javax.persistence.EntityManager em=ejb3_utility.Manager.open();
javax.persistence.EntityTransaction tx =em.getTransaction();
tx.begin();
em.persist(this);
tx.commit(); // or tx.rollback();
}finally {
ejb3_utility.Manager.close();
}
} // rien de particulier
Facult I&C, Claude Petitpierre
Transactions gres par version
public void modifier() {
try {
javax.persistence.EntityManager em =ejb3_utility.Manager.open();
javax.persistence.EntityTransaction tx =em.getTransaction();
tx.begin();
Produit2 p =em.merge(this);
p.prix ++;
tx.commit(); // or tx.rollback()
}finally {
ejb3_utility.Manager.close();
}
} // si un autre usager a modifi la mme JPA, une exception est
// leve car la version a chang depuis la dernire modification
Facult I&C, Claude Petitpierre
Transactions gres par version
public void modifier() {
try {
javax.persistence.EntityManager em =ejb3_utility.Manager.open();
javax.persistence.EntityTransaction tx =em.getTransaction();
tx.begin();
Produit2 p =em.merge(this); // reprend la version de lobjet pas celle
p.prix ++; // de la BD
tx.commit(); // or tx.rollback()
}finally {
ejb3_utility.Manager.close();
}
} // la deuxime modification, exception de mise jour
// car la version a chang depuis la dernire modification
Facult I&C, Claude Petitpierre
Transactions gres par version
(gestion correcte sans concurrence)
public void modifierAvecLecture() {
try {
javax.persistence.EntityManager em =ejb3_utility.Manager.open();
Query result =em.createQuery(
"SELECT p FROM Produit2 p WHERE p.nom='" +nom+"'");
Produit2 prod =(Produit2) result.getSingleResult();
// prod obtient la dernire valeur de la version
// suite comme dans le transparent prcdent
Facult I&C, Claude Petitpierre
MySQL
Pour initialiser MySQL sur les stations de la salle de l'EPFL, aller la
page http://www.mysql.com/downloads/mysql/ et charger l'avant-dernier
fichier .zip dans votre rpertoire.
Ouvrir une fentre terminal, aller dans le rpertoire bin du nouveau
rpertoire et appeler
mysqld u root console ou simplement mysqld
Les mots de passe, si vous en utilisez, doivent tre entrs dans le
fichier persistence.xml. Ouvrir ensuite une nouvelle fentre et appeler:
mysql
Vous pouvez ensuite taper des commandes telles celles-ci:
use test
show tables;
select * fromvin;
Facult I&C, Claude Petitpierre 51
Exercice
Entrer les produits de l'picerie dans la base de
donnes
Voir rsum sur J PA:
http://ltiwww.epfl.ch/~petitpie/ProgrammationInternet/J PA_Aux/J PA.html
Facult I&C, Claude Petitpierre
App Engine de Google
52
http://code.google.com/intl/fr/appengine/
Download the Google Plugin for Eclipse
Crez un compte
Dans Eclipse: New > Web Application Project
Clic droit sur le nom de projet > Web Application
(excution comme Tomcat)
Clic sur dans le menu principal >remplir champs
(excution sur serveur Google)
Erreurs: Sign up >application-id >logs
Fichiers pour crer un "disque" dans AppEngine:
http://lti.epfl.ch/Documents09_10/AppEngine/AppEngine.zip
Facult I&C, Claude Petitpierre
Documentation des J PAs
Essais avec J PA:
Remplacer / copier les fichiers ci-dessous dans le projet
Copier persistence.xml src/META-INF
http://ltiwww.epfl.ch/~petitpie/ProgrammationInternet/Google
Documentation:
Site App Engine >Getting started
Getting started >J ava (overview)
J ava (J PA)
53