5 - JPA Michel 2012
5 - JPA Michel 2012
5 - JPA Michel 2012
1
Michel Buffa (buffa@unice.fr), UNSA 2011
Note importante
Ce cours couvre les besoins les plus importants, vous pourrez retrouver un cours trs complet sur JPA2 et sur la persistence en java en gnral sur la page de Richard Grin
http://deptinfo.unice.fr/~grin/mescours/minfo/modper sobj/supports/index.html
Contexte
Contexte
Contexte
Rappel : l'tat d'un objet peut tre quelque chose de trs compliqu. Etat d'un objet = ses attributs, y compris les atributs hrits. Si les attributs sont eux-mme des instances d'une classe, il faut sauvegarder aussi les attributs de ces instances, etc
A partir d'un tat srialis, on peut reconstruire l'objet En java, au travers de l'interface java.io.Serializable, des mthodes de java.io.ObjectInputStream et java.io.ObjectOutputStream
Ex : on srialize mille comptes bancaires. Comment retrouver ceux qui ont un solde ngatif ?
On stocke l'tat d'un objet dans une base de donne. Ex : la classe Personne possde deux attributs nom et prenom, on associe cette classe une table qui possde deux colonnes : nom et prenom. On dcompose chaque objet en une suite de variables dont on stockera la valeur dans une ou plusieurs tables. Permet des requtes complexes.
Pas si simple
Dtermination de l'tat d'un objet parfois difficile, tout un art Il existe des produits pour nous y aider EclipseLink, TopLink (WebGain), Hibernate (JBoss), Aujourd'hui la plupart des gens font a la main avec JDBC ou SQL/J. Mais SQL dur tester/debugger source de
Les Base de donnes objet stockent directement des objets. Plus de mapping ! Object Query Language (OQL) permet de manipuler les objets Relations entre les objets videntes (plus de join ) Bonnes performances mais mauvaise scalabilit.
JPA 2 propose un modle standard de persistance laide des Entity beans Les outils qui assureront la persistance (Toplink, Hibernate, EclipseLink, etc.) sont intgrs au serveur dapplication et devront tre compatibles avec la norme JPA 2. Java EE 6 repose tous les niveaux sur de linjection de code via des annotations de code Souvent, on ne fera pas de new , les variables seront cres/initialises par injection de code.
Ce sont des objets qui savent se mapper dans une base de donne. Ils utilisent un mcanisme de persistance (parmi ceux prsents) Ils servent reprsenter sous forme d'objets des donnes situes dans une base de donne
Le plus souvent un objet = une ou plusieurs ligne(s) dans une ou plusieurs table(s)
Exemples
Compte bancaire (No, solde), Employ, service, entreprises, livre, produit, Cours, lve, examen, note,
Plus facile manipuler par programme, Vue plus compacte, on regroupe les donnes dans un objet. On peut associer des mthodes simples pour manipuler ces donnes On va gagner la couche middleware !
On lit les informations d'un compte bancaire en mmoire, dans une instance d'un entity bean, On manipule ces donnes, on les modifie en changeant les valeurs des attributs d'instance, Les donnes seront mises jour dans la base de donnes automatiquement ! Instance d'un entity bean = une vue en mmoire des donnes physiques
Schma classique :
La classe du bean se mappe dans une base de donnes. Cest une classe java normale (POJO) avec des attributs, des accesseurs, des modifieurs, etc. On utilisera les mta-donnes ou attributs de code pour indiquer le mapping, la cl primaire, etc. Cl primaire = un objet srializable, unique pour chaque instance. C'est la cl primaire au sens SQL. Note : on peut aussi utiliser un descripteur XML la place des annotations de code On manipulera les donnes de la BD laide des EntityBeans + laide dun PERSISTENT MANAGER. Le PM soccupera de tous les accs disque, du cache, etc. Lui seul contrle quand et comment on va accder la BD, cest lui qui gnre le SQL, etc.
Remarques gnrales
String vers VARCHAR(255) par dfaut, Les rgles peuvent changer dun SGBD lautre, par exemple String est mapp sur VARCHAR avec Derby, mais sur VARCHAR2 avec Oracle. Un Integer sur un INTEGER avec Derby mais sur un NUMBER avec Oracle. Etc. Dans le cas des cls primaires auto-incrmentes, la manire dont elles sont gres dpend du SGBD et de loutil de mapping relationnel-objet Si on en change -> la structure des tables change !
@stateless public class UnSessionBean { @PersistenceContext(unitName="EmployeeService") EntityManager em; public Employee createEmployee(int id, String name, long salary , byte[] pic) { Employee emp = new Employee(id); emp.setName(name); em.persist(emp); return emp; }
@stateless public class UnSessionBean { @PersistenceContext(unitName="EmployeeService") EntityManager em; public Employee createEmployee(int id, String name, long salary , byte[] pic) { Employee emp = new Employee(id); emp.setName(name); em.persist(emp); return emp; }
Autres annotations
@Entity public class Book { @Id @GeneratedValue(strategy = GenerationType.AUTO) private Long id; @Column(name = "book_title", nullable = false, updatable = false) private String title; private Float price; @Column(length = 2000) private String description; private String isbn; @Column(name = "nb_of_page", nullable = false) private Integer nbOfPage; private Boolean illustrations; @Basic(fetch = FetchType.LAZY) @Lob private byte[] audioText; // Constructors, getters, setters }
Attributs possibles : name, unique, nullable, insertable, updatable, table, length, precision, scale
@GeneratedValue
Indique la stratgie de gnration automatique des cls primaires, La valeur : GenerationType.auto est recommande, Va ajouter une table de squence
Souvent utilis avec @Basic(fetch = FetchType.LAZY) pour indiquer quon ne chargera lattribut que lorsquon fera un get dessus
Il se peut que les TPs en introduisent certaines. Les curieux peuvent consulter la spcification java EE 6 ou le tutorial (ou un bon livre)
<?xml version="1.0" encoding="UTF-8"?> <persistence version="1.0" mlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd"> <persistence-unit name="IGift-ejbPU" transaction-type="JTA"> <provider>org.hibernate.ejb.HibernatePersistence</provider> <jta-data-source>jdbc/igift</jta-data-source> <properties> <property name="hibernate.hbm2ddl.auto" value="update"/> </properties> </persistence-unit> </persistence>
Ce session bean est stateless, Utilise un EntityManager, Sert envoyer des requtes JPQL, Mthode persist(entity) pour crer une nouvelle entre (insert) Le reste passe par des appels de mthodes classiques de lentity bean.
Suite de lexemple
Survivent aux crashes du serveur, du SGBD Ce sont des vues sur des donnes dans un SGBD
Packager et dployer un Entity Bean Les EB sont dploys dans des persistence Units ,
Spcifi dans le fichier persistence.xml qui est dans le jar contenant les EJBs. Exemple le plus simple :
Mais on peut ajouter de nombreux paramtres : <description>, <provider>, <transaction type>, <mapping file> etc.
2.
3. 4.
New: le bean existe en mmoire mais nest pas encore associ une BD, il nest pas encore associ un contexte de persistence (via lentity manager) Managed : aprs le persist() par exemple. Le bean est associ avec les donnes dans la BD. Les changements seront rpercuts (transaction termines ou appel a flush()) Detached : le bean est nest plus associ au contexte de persistenced Removed : le bean est associ la BD, au contexte, et est programm pour tre supprim (les donnes seront supprimes aussi).
Remove() pour supprimer des donnes, Set(), Get(), appel de mthodes de lentity bean pour modifier les donnes, mais le bean doit tre dans un tat managed , Persist() pour crer des donnes, le bean devient manag, Merge pour faire passer un bean detached dans ltat managed .
Les entity beans correspondant des lignes dans une BD, on peut avoir besoin de faire des recherches. Similaire un SELECT Plusieurs fonctions sont proposes par lentity manager
Requtes SQL:
Requtes nommes:
Liste toutes les commandes qui ne comprennent pas (LEFT) de produit dont le prix est suprieur une certaine quantit (et celles qui ne comprennent pas de produits)
Requter sur plusieurs attributs renvoie soit un tableau dObject, soit une collection de tableaux dObject
texte = "select e.nom, e.salaire " + " from Employe as e"; query = em.createQuery(texte); List<Object[]> liste = (List<Object[]>)query.getResultList(); for (Object[] info : liste) { System.out.println(info[0] + "gagne" + info[1]); }
Expressions
MEMBER OF
Sous-Requtes
Similaire lexemple prcdent sauf que au lieu dutiliser @Embedded / @Embeddable on utilisera @EmbbededId / Embeddable
@Embeddable public class CompositeId { String name; String email } @Entity public class Dependent { @EmbeddedId // indique que la cl primaire est dans une autre classe CompositeId id; @ManyToOne Employee emp; }
Les entity beans reprsentant des donnes dans une BD, il est logique d'avoir envie de s'occuper de grer des relations Exemples
Une commande et des lignes de commande Une personne et une adresse Un cours et les lves qui suivent ce cours Un livre et ses auteurs
Nous allons voir comment spcifier ces relations dans notre modle EJB
Concepts abords
Cardinalit (1-1, 1-n, n-n ), Direction des relations (bi-directionnelles, unidirectionnelles), Agrgation vs composition et destructions en cascade, Relations rcursives, circulaires, agressive-load, lazyload, Intgrit rfrentielle, Accder aux relations depuis un code client, via des Collections, Comment grer tout a !
Unidirectionnelle
Bidirectionnelle
Cardinalit
La cardinalit indique combien d'instances vont intervenir de chaque ct d'une relation One-to-One (1:1)
One-to-Many (1:N)
Many-to-Many (M:N)
Cardinalit
Relations 1:1
Reprsente typiquement par une cl trangre dans une BD Ex : une commande et un colis
Exemple de code pour insrer une commande avec une livraison relie
On peut maintenant ajouter au code de tout lheure (celui qui crit une commande) :
Relations 1:N
Relations 1:N
Exemple de client
Version bidirectionnelle
Version bidirectionnelle
Version bidirectionnelle
Relations M:N
Un tudiant suit plusieurs cours, un cours a plusieurs tudiants inscrits
Quon soit en prsence dun modle normalis ou pas, les outils dORM sadaptent.
Schma normalis
Schma dnormalis
Choisir la directionalit ?
Premier critre : la logique de votre application, Second critre : si le schma relationnel existe, s'adapter au mieux pour viter de mauvaises performances.
Agressive-loading
Lorsqu'on charge un bean, on charge aussi tous les beans avec lesquels il a une relation. Cas de la Commande et des Colis plus tt dans ce chapitre. Peut provoquer un norme processus de chargement si le graphe de relations est grand.
Lazy-loading
On ne charge les beans en relation que lorsqu'on essaie d'accder l'attribut qui illustre la relation. Tant qu'on ne demande pas quels cours il suit, le bean Etudiant n'appelle pas de mthode finder sur le bean Cours.
Le bean utilise un autre bean Consquence : si le bean A utilise le bean B, lorsqu'on dtruit A on ne dtruit pas B. Par exemple, lorsqu'on supprime un tudiant on ne supprime pas les cours qu'il suit. Et vice-versa.
Le bean se compose d'un autre bean. Par exemple, une commande se compose de lignes de commande Si on dtruit la commande on dtruit aussi les lignes correspondantes. Ce type de relation implique des destructions en cascade..
Relations et JPQL
Lorsqu'on dfinit une relation en CMP, on peut aussi indiquer la requte qui permet de remplir le champs associ la relation. On fait ceci l'aide de JPQL SELECT o.customer FROM Order o
Renvoie tous les clients qui ont plac une commande
Relations et EJB-QL
Relations rcursives
Exemple : Employ/Manager
Rien de particulier, ces relations sont implmentes exactement comme les relations non rcursives
Relations circulaires
Ex : un employ travaille dans une division, une division possde plusieurs ordinateurs (workstation), une workstation est alloue un employ
Ce type de relation, en cas de agressive-loading peut mener une boucle sans fin
Relations circulaires
2. 3. 4. 5.
Certains containers proposent d'optimiser le chargement d'un bean en chargeant toutes ses relations en cascade. Attention si relations circulaires ! Supprimer une des relations (!!!) si le modle de conception le permet. Supprimer la bidirectionnalit d'une des relations pour briser le cercle, si le modle de conception le permet. Utiliser le lazy-loading et ne pas faire de destruction en cascade. Les meilleurs moteurs CMP dtectent les relations circulaires et vous permettent de traiter le problme avant le runtime.
Intgrit rfrentielle
a des
Si on supprime un employ, il faut vrifier qu'il est bien supprim partout o on a une relation avec lui.
Intgrit rfrentielle
Grer l'intgrit dans le SGBD est intressant si la BD est attaque par d'autres applications que les EJBs Autre approche : grer l'intgrit dans les EJBs
Solution plus propre, Le SGBD n'est plus aussi sollicit, Avec les EJB: le travail est fait tout seul !
Intgrit rfrentielle
Et dans un contexte distribu ? Plusieurs serveurs d'application avec le mme composant peuvent accder des donnes sur le mme SGBD, Comment mettre jour les relations ? Problme rsolu par les transactions !!!
Lorsquon accde aux relations par un getter, on ne contrle pas par dfaut lordre des lments. Plusieurs solutions sont possibles pour rcuprer des relations sous forme de collections tries
Utiliser lannotation @OrderBy juste avant la dclaration de la relation ou juste avant le getter Utiliser une requte avec un Order By Annoter lattribut correspondant la colonne qui sera ordonne, dans lentity de la relation
Remarques
ASC ou DESC pour lordre de tri, ASC par dfaut, lastname est une proprit de lentit Student.java, Si la proprit nest pas spcifie -> tri par lid
Remarques
ASC ou DESC pour lordre de tri, ASC par dfaut, lastname est une proprit de lentit Student.java, Si la proprit nest pas spcifie -> tri par lid
On peut utiliser loprateur . si on trie sur une colonne qui est dfinie dans une autre classe par @Embedded
@Entity public class Person { ... @ElementCollection @OrderBy("zipcode.zip, zipcode.plusFour") Set<Address> residences; ... }
Introduction
Hritage
Un exemple !
Code de Motorcycle.java
Code de Car.java
Code de Roadster.java
Code de Coupe.java
Une seule table reprsente toute la hirarchie. Une colonne de discrimination est utilise pour distinguer les sous-classes. Cette solution supporte le polymorphisme. Dsavantages :
Une colonne pour chaque champ de chaque classe, Comme une ligne peut tre une instance de chaque classe, des champs risquent de ne servir rien (nullable)
(suite)
Motorcycle.java annot !
Car.java annot
Roadster.java annot
Coupe.java annot
Table correspondante
Dans RoadVehicle.java
On peut retirer les @Discriminator des sous-classes (on aura des valeurs par dfaut) Le champ Id de la classe RoadVehicle sera une cl trangre dans les tables des sous-classes, Remarque : on utilise ici @TABLE pour ne pas que la table porte le mme nom que dans lexemple prcdent (facultatif)
Les tables !
Il faut faire des joins ! Plus la hierarchie est profonde, plus il y aura de jointures : problmes de performance !
Supporte le polymorphisme, On alloue juste ce quil faut sur disque, Excellente approche si on a pas une hirarchie trop profonde, A viter sinon
Autres approches
Des classes qui sont des entity bean peuvent hriter de classes qui nen sont pas, Des classes qui ne sont pas des entity beans peuvent hriter de classes qui en sont, Des classes abstraites peuvent tre des entity beans, (dj vu : une classe qui est un entity bean hrite dune autre classe qui est un entity bean)
RoadVehicle naura jamais sa propre table, Les sous-classes auront leur propre table, avec comme colonnes les attributs de RoadVehicle en plus des leurs, Si on navait pas mis @MappedSuperclass dans RoadVehicle.java, les attributs hrits nauraient pas t des colonnes dans les tables des sous-classes.
Une classe abstraite peut tre un entity bean (avec @entity) Elle ne peut pas tre instancie, ses sousclasses concrtes oui, Elle aura une table ddie, Elle pourra faire lobjet de requtes (polymorphisme) : trs intressant !
Polymorphisme (suite)
Cest bien la mthode toString() de chaque sous-classe qui est appele ! La requte rcupr tous les RoadVehicle (s)
Liste toutes les commandes qui ne comprennent pas (LEFT) de produit dont le prix est suprieur une certaine quantit (et toutes celles qui nont pas de produits)
Celle-l en ramne trois aussi (le left matche celles qui nont pas de jointure)
Expressions
MEMBER OF
Sous-Requtes
Message-Driven Beans
Michel Buffa (buffa@unice.fr), UNSA 2011
Message-Driven Beans
Nouveaut apparue avec EJB 2.0, Messaging = moyen de communication lger, compar RMI-IIOP, Pratique dans de nombreux cas, Message-Driven beans = beans accessibles par messaging asynchrone.
Performance
Un client RMI-IIOP attend pendant que le serveur effectue le traitement d'une requte,
Fiabilit
Lorsqu'un client RMI-IIOP parle avec un serveur, ce dernier doit tre en train de fonctionner. S'il crashe, ou si le rseau crashe, le client est coinc.
Pas de broadcasting !
Messaging
C'est comme le mail ! Ou comme si on avait une troisime personne entre le client et le serveur !
Messaging
A cause de ce "troisime homme" les performances ne sont pas toujours au rendez-vous ! Message Oriented Middleware (MOM) est le nom donn aux middlewares qui supportent le messaging.
Tibco Rendezvous, IBM MQSeries, BEA Tuxedo/Q, Microsoft MSMQ, Talarian SmartSockets, Progress SonicMQ, Fiorano FioranoMQ, Ces produits fournissent : messages avec garantie de livraison, tolrance aux fautes, load-balancing des destinations, etc
Les serveurs MOM sont pour la plupart propritaires : pas de portabilit des applications ! JMS = un standard pour normaliser les changes entre composant et serveur MOM,
Une API pour le dveloppeur, Un Service Provider Interface (SPI), pour rendre connecter l'API et les serveurs MOM, via les drivers JMS
Domaines possibles
Publish/Subscribe (pub/sub) : n producteurs, n consommateurs (tv) Point To Point (PTP) : n producteurs, 1 consommateur
lookup JNDI. Le driver est une connection factory obtenir une connection partir de la connection factory Il s'agit d'un objet qui va servir recevoir et envoyer des messages. On l'obtient partir de la connection. Il s'agit du canal, de la chane tl ! Normalement, c'est rgl par le dployeur. On obtient la destination via JNDI. Utiliss pour crire ou lire un message. On les obtient partir de la destination ou de la session.
2.
3.
4.
5.
6.
Note : Dans 3) false = pas de transactions, AUTO_AKNOWLEDGE = inutile ici puisquon envoie des messages.
Pourquoi crer un nouveau type d'EJB ? Pourquoi ne pas avoir dlgu le travail un objet spcialis ? Pourquoi ne pas avoir augment les caractristiques des session beans ? Parce que ainsi on peut bnficier de tous les avantages dj rencontrs : cycle de vie, pooling, descripteurs spcialiss, code simple
Il consomme des messages depuis les queues ou topics, envoys par les clients JMS
Un client n'accde pas un MDB via une interface, il utilise l'API JMS, Un MDB n'a pas d'interface Home, Local Home, Remote ou Local, Les MDB possdent une seule mthode, faiblement type : onMessage()
Elle accepte un message JMS (BytesMessage, ObjectMessage, TextMessage, StreamMessage ou MapMessage) Pas de vrification de types la compilation. Utiliser instanceof au run-time pour connatre le type du message.
Pour envoyer une rponse l'expditeur : plusieurs design patterns Les MDB ne renvoient pas d'exceptions au client (mais au container), Les MDB sont stateless Les MDB peuvent tre des abonns durables ou nondurables (durable or nondurable subscribers) un topic
Durable = reoit tous les messages, mme si l'abonn est inactif, Dans ce cas, le message est rendu persistant et sera dlivr lorsque l'abonn sera de nouveau actif. Nondurable = messages perdus lorsque abonn inactif.
Le consommateur (celui qui peut les dtruire) des messages est en gnral le Container
C'est lui qui choisit d'tre durable ou non-durable, S'il est durable, les messages rsistent au crash du serveur d'application.
La classe d'implmentation doit fournir une mthode ejbCreate() qui renvoit void et qui n'a pas d'arguments.
onMessage(Message)
Invoque
chaque consommation de message Un message par instance de MBD, pooling assur par le container setMessageDrivenContext(MessageDrivenC ontext)
Appele
avant ejbCreate, sert rcuprer le contexte. Ne contient que des mthodes lies aux transactions
Un exemple simple
Un MDB qui fait du logging, c'est dire affiche des messages de textes l'cran chaque fois qu'il consomme un message.
La classe du bean
Question ?
C'est fait exprs pour rendre les MDB portables et rutilisables. L'information se trouve dans l@ActivationConfigProperty au dbut du code
Le client (1)
import javax.naming.*;
public class Client { public static void main (String[] args) throws Exception { // Initialize JNDI Context ctx = new InitialContext(System.getProperties());
Le client (2)
// 6: Create a text message, and publish it TextMessage msg = session.createTextMessage(); msg.setText("This is a test message."); publisher.publish(msg); } }
Concepts avancs
Transactions et MBD,
Scurit,
Les MDB ne reoivent pas les informations de scurit du producteur avec le message. On ne peut pas effectuer les oprations classiques de scurit sur les EJB.
Load-Balancing,
Modle idal : les messages sont dans une queue et ce sont les MDB qui consomment, d'o qu'ils proviennent. Comparer avec les appels RMI-IIOP pour les session et entity beans, ou on ne peut que faire des statistiques
Concepts avancs
Consommation duplique dans les architectures en clusters : utiliser une queue au lieu d'un topic si on veut que le message ne soit consomm qu'une fois ! Chaque container est un consommateur !
Concepts avancs
Piges !
L'appel ejbRemove() n'est pas garanti, comme pour les session beans stateless
A cause du pooling, En cas de crash.
Piges !
MDB empoisonn !
package examples;
public void setMessageDrivenContext(MessageDrivenContext ctx) { this.ctx = ctx; } public void ejbCreate() {} public void ejbRemove() {} ...
MDB empoisonn !
... public void onMessage(Message msg) try { System.out.println("Received msg " + msg.getJMSMessageID()); // Let's sleep a little bit so that we don't see rapid fire re-sends of the message. Thread.sleep(3000); {
// We could either throw a system exception here or // manually force a rollback of the transaction. ctx.setRollbackOnly(); } catch (Exception e) { e.printStackTrace(); } } }
MDB empoisonn !
Solutions
Ne pas lever d'exception, Utiliser des transactions gres par le bean, non par le container, Certains serveurs peuvent configurer une "poison message queue" ou possder un paramtre "nb max retries"
Nanmoins, des problmes se posent si le client est lui-mme un EJB de type stateful session bean
Que se passe-t-il en cas de passivation ? Perte de la connexion la destination temporaire!
Solution : ne pas utiliser d'EJB SSB comme client! Utiliser une Servlet ou un JSP Autre solution : configurer un topic permanent pour les rponses, au niveau du serveur JMS.
D'autres solutions existent JMS propose deux classes javax.jms.QueueRequestor et javax.jms.TopicRequestor qui implmentent une pattern simple question/rponse Solution bloquante, pas de gestion de transactions JAVA EE 6: invocation de mthode asynchrone !