La descarga está en progreso. Por favor, espere

La descarga está en progreso. Por favor, espere

Disseny de la persistència JDO i frameworks de persistència

Presentaciones similares


Presentación del tema: "Disseny de la persistència JDO i frameworks de persistència"— Transcripción de la presentación:

1 Disseny de la persistència JDO i frameworks de persistència
Toni Navarrete Enginyeria del Software II – UPF 2005

2 Recordatori: problemes (i aventatges) d’altres solucions
Serialitzatió Avantantges: Estàndard en qualsevol ambient Java Fàcil d’utilitzar El model de dades és directament el de les classes (aprofita OO) Inconvenients: No té les característiques d’un gestor de BD robust Per exemple, índexs, transaccions,... No és escalable

3 Recordatori: problemes (i aventatges) d’altres solucions
JDBC Dóna accés a SQL Usa el model relacional de SQL No el model orientat a objectes de Java Procedimental en lloc d’OO El processament de dades es fa mitjançant SQL i no Java Les operacions són expressades en relació a taules, files i columnes SQL no està realment estandaritzat, amb la qual cosa la portabilitat no sempre és real

4 Recordatori: problemes (i aventatges) d’altres solucions
Quan s’utilitza JDBC, el programador està obligat a treballar amb dos models de dades diferents, així com amb dos paradigmes i llenguatges d’accés a les dades distints. El resultat sol ser que s’escriu codi Java procedural per manipular les taules. No OO

5 Conseqüència Moltes organitzacions comencen a desenvolupar el seu propi framework per a persistència i O/R mapping, que permeti els seus objectes interactuar amb la BD de forma transparent Exemples Castor Apache ObJectRelationalBridge (OJB) ODMG 3.0, desenvolupat pel Object Data Management Group (ODMG). Inicalment en C++ i Smaltalk, ha estat una de les bases de JDO i n’és un subconjunt

6 Problemes (i avantatges) d’altres solucions
ORM propietaris (Object-Relational Mapping) Riscos significatius a l’hora de desenvolupar un ORM propi Limitacions d’APIs ORM propietàries. Adoptar un API propietària és sempre arriscat. A moltes implementacions: Falta d’encapsulació causada per la necessitat de definir mètodes getter i setter públics per als atributs persistents Extensibilitat limitada per la falta de soport de l’herència Falta de soport de referències polimòrfiques Dependència absoluta d’un venedor

7 JDO És una nova iniciativa de la comunitat Java per crear un framework estandaritzat per a persistència (de la mateixa que Swing ho és per a interfície gràfica) JDO és només una especificació, de la qual els fabricants de software faran implementacions (a vegades lliures, a vegades no) Normalment parlarem de JDO per accedir a BDR, però pot ser qualsevol forma d’emmagatzemantge permanent (XML, fitxers,...) Sun produeix el JDORI (JDO Reference Implementation) com a una implementació per demostrar que l’especificació és vàlida. Però no està pensada per explotació en entorns reals

8 JDO JDO: capacitats de BD de JDBC amb la integració Java de la serialització JDO usa el model d’objectes Java Les instàncies tenen un identificador únic (OID únic) Soporta transaccions Emmagatzemar instàncies, recuperar-les i modificar-es és transparent Resum: mínima intrusió i màxima transparència

9 Comparació JDO amb les altres alternatives
EJB també defineix un mecanisme de persistència transparent (Container Managed Persistence, CMP), però EJB és una arquitectura complexa i amb més overhead que JDO Serialització també és OO però no és apte per treballar amb grans volums de dades, no és escalable, i no té suport per índexs, transaccions i demés mecanismes d’un SGBD

10 JDO no substituirà JDBC
JDO i JDBC JDO no substituirà JDBC Són complementàries Les implementacions de JDO solen utilitzar JDBC per sota per connectar-se a la BD JDBC és útil per gestionar connexions amb la BD JDBC és força sòlid JDBC està soportat per la majoria de fabricants de SGBC

11 JDO JDOcentral.com: A comparion between Java Data Objects (JDO), Serialization and JDBC for Java Persistance

12 Exemple d’una petita aplicació JDO amb la JDORI

13 Exemple d’una classe persistent amb JDO
package es2; public class Persona { String nom, cognom; int anyNaixement = 0; public Persona() {} // a JDO és obligatori que hi hagi un constructor sense arguments public Persona(String nom, String cognom, int anyNaixement) { this.nom = nom; this.cognom = cognom; this. anyNaixement = anyNaixement; } public void setNom(String nom) { public String getNom() { return this.nom; public void setCognom(String cognom) { public String getCognom() { return this.cognom; public void setAnyNaixement(int anyNaixement) { public int getAnyNaixement() { return this.anyNaixement;

14 Declaració de classes persistents
L’únic requeriment és que la classe ha de tenir un constructor sense arguments Ara podem crear instàncies d’aquesta classe Person i guardar-las a la BDR JDO utilitza un fitxer de metadades per dir quines classes seran persistents i reflectir tota la informació relacionada amb la persistència (ho veurem amb més detall més endavant) Fitxer amb extensió .jdo

15 Exemple de fitxer de metadades (es2.jdo)
<?xml version= "1.0" encoding="UTF-8"?> <!DOCTYPE jdo SYSTEM "file:/C:/.../jdori-1_0/srcjavax/jdo/jdo.dtd"> <jdo> <package name= "es2" > <class name="Persona" /> </package> </jdo> o <!DOCTYPE jdo PUBLIC “-//Sun Microsystems, Inc.//DTD Java Data Objects Metadata 1.0//EN" " Nota: algunes implementacions fixen com s’ha d’anomenar el fitxer de metadades

16 Jars necessaris JDO es pot baixar de www.jcp.org (JSR-12)
Per treballar amb la implementació de referència: jdo.jar Les interfícies estàndard i les classes definides a l’especificació JDO jdori.jar La implementació de referència de Sun btree.jar Implementa un petit gestor d’emmagatzament per la JDORI de Sun jta.tar Java Transaction API que usa JDO per definir transaccions antlr.jar Serveix per parsejar el llenguatges de consultes de JDO xerces.jar Per parsejar XML

17 Enhancement Un cop que hem compilat la(s) classe(s), hem de fer un enhancement Això sobre-escriu els fitxers de bytecode (.class) afegint dades i mètodes que permeten les instàncies de la classe ser manegades per la implementació JDO Ho fa a partir del fitxer de metadades Cada fabricant de JDO pot incloure el seu enhancer, però suposadament són compatibles JDORI porta el reference enhancer

18 Enhancement

19 Enhancement

20 Enhancement java com.sun.jdori.enhancer.Main es2.jdo es2/Persona.class
Algunes opcions: -v (verbose) -d (a un directori distint, sense sobreescriure el .class original): java com.sun.jdori.enhancer.Main -v -d enhanced es2.jdo es2/Persona.class Cada fabricant d’implementacions JDO té el seu enhancer que es crida de forma diferent Noteu que l’enhancement és independent del magatzem de dades que utilitzem després

21 Fent una aplicació Ara farem una aplicació que crea instàncies de Persona i les guarda a una BD JDORI porta un petit gestor com a referència que es diu FOStore (File Object Store)

22 Estructura de classes de JDO
El nucli de JDO és la interfície PersistenceManager, que és la que manega la connexió amb un magatzem de dades

23 Estructura de classes de JDO
Per obtenir i configurar un PersistenceManager es fa mitjançant la interfície PersistenceManagerFactory A la vegada, el PersistenceManagerFactory s’obté a partir d’un mètode estàtic de la classe JDOHelper, segons unes propietats (url de connexió, login, password i el nom de la implementació de JDO que utilitzem)

24 Estructura de classes de JDO
Exemple de propietats per crear un PersistenceManagerFactory: javax.jdo.PersistenceManagerFactoryClass=com.sun.jdori.fostore.FOStorePMF javax.jdo.option.ConnectionURL =fostore:database/fostoredb javax.jdo.option.ConnectionUserName=toni javax.jdo.option.ConnectionPassword=toni Aquestes propietats poden estar a un fitxer (típicament jdo.properties) o ser configurades des de programa

25 Estructura de classes de JDO
Un PersistenceManager té associat una instància de la interfície JDO Transaction, per a controlar el començament i finalització d’una transacció Per obtenir la instància de Transaction ho fem amb el mètode currentTransaction de la instància de PersistenceManager En JDO tota acció que hagi de modificar la BD estarà emmarcada dins d’una transacció Usarem els mètodes begin, commit i rollback de la instància de Transaction

26 FOStore JDORI porta un petit gestor com a referència que es diu FOStore (File Object Store) Anem a crear una BD per guardar les futures instàncies de la classe Persones jdo.properties Directori database CreateDatabase.java

27 Creació d’una BD en FOStore
package es2; import java.io.FileInputStream; import java.io.InputStream; import java.util.Properties; import javax.jdo.JDOHelper; import javax.jdo.PersistenceManagerFactory; import javax.jdo.PersistenceManager; import javax.jdo.Transaction; public class CreateDatabase{ public static void main(String[] args){ create(); } public static void create(){ try{ InputStream propertyStream = new FileInputStream("es2/jdo.properties"); Properties jdoproperties = new Properties(); jdoproperties.load(propertyStream); jdoproperties.put("com.sun.jdori.option.ConnectionCreate","true"); PersistenceManagerFactory pmf = JDOHelper.getPersistenceManagerFactory(jdoproperties); PersistenceManager pm = pmf.getPersistenceManager(); Transaction tx = pm.currentTransaction(); tx.begin(); tx.commit(); } catch (Exception e) { System.err.println("Exception creating db"); e.printStackTrace(); System.exit(-1); Aquest codi crea un magatzem al directori database Propietat com.sun.jdori.option.ConnectionCreate a true

28 Creant l’aplicació package es2; import java.io.FileInputStream;
import java.io.InputStream; import java.util.Properties; import java.util.Map; import java.util.HashMap; import javax.jdo.JDOHelper; import javax.jdo.PersistenceManagerFactory; import javax.jdo.PersistenceManager; import javax.jdo.Transaction; public class Aplicacio1{ protected PersistenceManagerFactory pmf; protected PersistenceManager pm; protected Transaction tx; public Aplicacio1() { try{ InputStream propertyStream = new FileInputStream("es2/jdo.properties"); Properties jdoproperties = new Properties(); jdoproperties.load(propertyStream); pmf = JDOHelper.getPersistenceManagerFactory(jdoproperties); pm = pmf.getPersistenceManager(); tx = pm.currentTransaction(); } catch (Exception e) { System.err.println("Exception creating db"); e.printStackTrace(); System.exit(-1); } public void executeTransaction() { tx.begin(); Persona p = new Persona("toni","navarrete",1973); pm.makePersistent(p); tx.commit(); } catch (Throwable exception){ exception.printStackTrace(System.err); if (tx.isActive()) tx.rollback(); public static void main(String[] args) { Aplicacio1 ap = new Aplicacio1(); ap.executeTransaction(); Creant l’aplicació

29 També es poden especificar les propietats dins del codi:
Sobre les propietats També es poden especificar les propietats dins del codi: ... Properties props = new Properties(); props.setProperty("javax.jdo.PersistenceManagerFactoryClass", "com.sun.jdori.fostore.FOStorePMF "); props.setProperty("javax.jdo.option.ConnectionURL", "fostore:database/fostoredb"); props.setProperty("javax.jdo.option.ConnectionUserName",“toni"); props.setProperty("javax.jdo.option.ConnectionPassword",“toni"); props.setProperty("javax.jdo.option.Optimistic",“false"); pmf = JDOHelper.getPersistenceManagerFactory(jdoproperties);

30 Creant l’aplicació amb una millor organització
package es2; import java.io.FileInputStream; import java.io.InputStream; import java.util.Properties; import javax.jdo.JDOHelper; import javax.jdo.PersistenceManagerFactory; import javax.jdo.PersistenceManager; import javax.jdo.Transaction; public abstract class Aplicacio{ protected PersistenceManagerFactory pmf; protected PersistenceManager pm; protected Transaction tx; public abstract void execute(); public Aplicacio() { try{ InputStream propertyStream = new FileInputStream("es2/jdo.properties"); Properties jdoproperties = new Properties(); jdoproperties.load(propertyStream); pmf = JDOHelper.getPersistenceManagerFactory(jdoproperties); pm = pmf.getPersistenceManager(); tx = pm.currentTransaction(); } catch (Exception e) { System.err.println("Exception creating db"); e.printStackTrace(); System.exit(-1); } public void executeTransaction() { tx.begin(); execute(); tx.commit(); } catch (Throwable exception){ exception.printStackTrace(System.err); if (tx.isActive()) tx.rollback(); Creant l’aplicació amb una millor organització package es2; public class CrearPersones extends Aplicacio{ public static void main(String[] args) { CrearPersones cp = new CrearPersones(); cp.executeTransaction(); } public void execute() { Persona p1 = new Persona("pasqual","maragall",1950); pm.makePersistent(p1); Persona p2 = new Persona("artur","mas",1955); pm.makePersistent(p2);

31 Mètode getExtent del PersistenceManager
Consultes Extent és una interfície que permet accedir a totes les instàncies d’una classe persistent Mètode getExtent del PersistenceManager Extent extent = pm.getExtent(Persona.class,false); /* el segon paràmetre indica si també considerar les instàncies de les subclasses */

32 Consulta de totes les persones emmagatzemades
package es2; import java.util.Iterator; import javax.jdo.Extent; public class LlistatPersones extends Aplicacio{ public static void main(String[] args) { LlistatPersones lp = new LlistatPersones(); lp.executeTransaction(); } public void execute() { Extent extent = pm.getExtent(Persona.class,false); Iterator it = extent.iterator(); while (it.hasNext()) { Persona p = (Persona)it.next(); System.out.println("Nom: " + p.getNom()); System.out.println("Cognom: " + p.getCognom()); System.out.println("Any naixement: " + p.getAnyNaixement()); System.out.println(); extent.close(it); Consulta de totes les persones emmagatzemades

33 Consulta de totes les persones emmagatzemades (sense transacció)
package es2; import java.util.Iterator; import javax.jdo.Extent; public class LlistatPersones extends Aplicacio{ public static void main(String[] args) { LlistatPersones lp = new LlistatPersones(); lp.consulta(); } public void consulta() { Extent extent = pm.getExtent(Persona.class,false); Iterator it = extent.iterator(); while (it.hasNext()) { Persona p = (Persona)it.next(); System.out.println("Nom: " + p.getNom()); System.out.println("Cognom: " + p.getCognom()); System.out.println("Any naixement: " + p.getAnyNaixement()); System.out.println(); extent.close(it); public void execute() {} Consulta de totes les persones emmagatzemades (sense transacció)

34 Consultes i filtres La interfície Query permet definir filtres sobre un Extent, per fer consultes més específiques (i no de tots els elements) Quan es crea una Query s’especifica l’Extent i la condició: Query q = pm.newQuery(extent,"nom == nomPersona"); q.declareParameters("String nomPersona"); També es pot crear la Query directament sobre la classe: Query q = pm.newQuery(Persona.class,"nom==\"toni\""); En especificar la condició podem utilitzar els operadors comparatius, aritmètics,... de Java

35 Consulta del cognom d’una persona concreta
package es2; import java.util.Iterator; import java.util.Collection; import javax.jdo.Extent; import javax.jdo.Query; public class CognomPersona extends Aplicacio{ public static void main(String[] args) { CognomPersona cp = new CognomPersona(); cp.executeTransaction(); } public void execute() { Extent extent = pm.getExtent(Persona.class,false); String nomPersona = new String("toni"); Query q = pm.newQuery(extent,"nom == nomPers"); q.declareParameters("String nomPers"); Collection result = (Collection)q.execute(nomPersona); Iterator it = result.iterator(); if (it.hasNext()) { Persona p = (Persona)it.next(); System.out.println("Nom: " + p.getNom()); System.out.println("Cognom: " + p.getCognom()); System.out.println("Any naixement: " + p.getAnyNaixement()); q.close(result); Consulta del cognom d’una persona concreta

36 Més coses Treballar amb un gestor de veritat
Una altra implementació de JDO: JPOX És opensource i té suport per treballar amb nombrosos SGBDs (MySQL, PostgreSQL i Oracle entre d’altres) Des de la versió 1.1 suporta JDO 2.0 i de fet n’és la nova implementació de referència Associacions entre classes (relacions entre taules) i herència Generació automàtica de l’esquema de la BD Capacitat per configurar el mapping objecte/relacional a l’hora de crear les taules Permet: Insercions, eliminacions i modificacions d’objectes Consultes Persistència transitiva

37 Un exemple més complet (amb JPOX)
Persona Grup 0..* 0..1 Empleat

38 Persona package es2; public class Persona { String nom, cognom;
int anyNaixement = 0; Grup grupp; public Persona() {} // a JDO és obligatori que hi hagi un constructor sense arguments public Persona(String nom, String cognom, int anyNaixement) { this.nom = nom; this.cognom = cognom; this. anyNaixement = anyNaixement; } public void setNom(String nom) { this.nom = nom; } public String getNom() { return this.nom; } public void setCognom(String cognom) { this.cognom = cognom; } public String getCognom() { return this.cognom; } public void setAnyNaixement(int anyNaixement) { this. anyNaixement = anyNaixement; } public int getAnyNaixement() { return this.anyNaixement; } public void setGrup(Grup g) { this.grupp = g; } public Grup getGrup() { return this.grupp;

39 Grup Suporta diversos tipus per a les col·leccions: Collection Set
package es2; import java.util.*; public class Grup { String nom; Set persones; public Grup() {} // a JDO és obligatori que hi hagi un constructor sense arguments public Grup(String nom) { this.nom=nom; this.persones=new HashSet(); } public void setNom(String nom) { this.nom = nom; public String getNom() { return this.nom; public void afegeixPersona(Persona p) { this.persones.add(p); p.setGrup(this); public Set getPersones() { return this.persones; Suporta diversos tipus per a les col·leccions: Collection Set HashSet Map List ArrayList HashMap Hashtable LinkedList TreeMap TreeSet Vector

40 Empleat package es2; public class Empleat extends Persona{ int salari;
public Empleat() {} // a JDO és obligatori que hi hagi un constructor sense arguments public Empleat(String nom, String cognom, int anyNaixement, int salari) { this.nom = nom; this.cognom = cognom; this.anyNaixement = anyNaixement; this.salari=salari; } public void setSalari(int salari) this.salari = salari; public int getSalari() return this.salari; Empleat

41 Fitxer de metadades (package.jdo)
<?xml version="1.0"?> <!DOCTYPE jdo PUBLIC "-//Sun Microsystems, Inc.//DTD Java Data Objects Metadata 1.0//EN" " <jdo> <package name="es2"> <class name="Persona"> <field name="grupp" persistence-modifier="persistent" /> </class> <class name="Empleat" persistence-capable-superclass="es2.Persona"/> <class name="Grup"> <field name="persones" mapped-by="grupp"> <collection element-type="es2.Persona"/> </field> </package> </jdo> Comanda d’Enhancement: java -cp "build;lib/jpox.jar;lib/jpox-enhancer.jar;lib/bcel.jar;lib/jdo.jar; lib/log4j.jar" org.jpox.enhancer.JPOXEnhancer build/es2/package.jdo NOTA: aquest fitxer de metadades és per a JDO 1 (JPOX 1.0). Més endavant es veurà com definir l’herència de forma precisa per a JDO 2 (JPOX 1.1)

42 Extensions als elements de metadades
Els fabricants d’implementacions JDO poden crear les seves extensions als elements del fitxers de metadades Lògicament no seran portables a altres implementacions Es poden definir paràmetres referents a com emmagatzemar les dades, com per exemple crear índexs, definir primary-keys, especificar longituds de strings,... Exemple: <field name="name"> <extension vendor-name="jpox“ key="length" value="max 100"/> </field> JDO 2.0 ja integra moltes d’aquestes extensions de forma estàndard. Per exemple <field name=“name" persistence-modifier="persistent"> <column length=“100" jdbc-type="VARCHAR"/>

43 Tractament de les relacions. Relacions 1 a 1
Single-ended <package name="mydomain"> <class name="User" identity-type="datastore"> <field name="login" persistence-modifier="persistent"> <column length=“20" jdbc-type="VARCHAR"/> </field> </class> <class name="Account" identity-type="datastore"> <field name="firstName" persistence-modifier="persistent"> <column length=“50" jdbc-type="VARCHAR"/> <field name="secondName" persistence-modifier="persistent"> <field name="user" persistence-modifier="persistent"> </package>

44 Tractament de les relacions. Relacions 1 a 1
Double-ended <package name="mydomain"> <class name="User" identity-type="datastore"> <field name="login" persistence-modifier="persistent"> <column length=“20" jdbc-type="VARCHAR"/> </field> <field name="account" persistence-modifier="persistent"> </class> <class name="Account" identity-type="datastore"> <field name="firstName" persistence-modifier="persistent"> <column length=“50" jdbc-type="VARCHAR"/> </field> <field name="secondName" persistence-modifier="persistent"> <column length=“50" jdbc-type="VARCHAR"/> <field name="user" persistence-modifier="persistent"> </package>

45 Tractament de les relacions. Relacions 1 a N
Unidireccional amb foreign key: <package name="mydomain"> <class name="Account" identity-type="datastore"> <field name="firstName" persistence-modifier="persistent"> <column length="100" jdbc-type="VARCHAR"/> </field> <field name="lastName" persistence-modifier="persistent"> <field name="addresses" persistence-modifier="persistent"> <collection element-type=" mydomain.Address"/> </class> <class name="Address" identity-type="datastore"> <field name="city" persistence-modifier="persistent"> <column length="50" jdbc-type="VARCHAR"/> <field name="street" persistence-modifier="persistent"> </package>

46 Tractament de les relacions. Relacions 1 a N
Bidireccional amb foreign key: <package name="mydomain"> <class name="Account" identity-type="datastore"> <field name="firstName" persistence-modifier="persistent"> <column length="100" jdbc-type="VARCHAR"/> </field> <field name="lastName" persistence-modifier="persistent"> <field name="addresses" persistence-modifier="persistent" mapped-by="account"> <collection element-type=“mydomain.Address"/> </class> <class name="Address" identity-type="datastore"> <field name="city" persistence-modifier="persistent"> <column length="50" jdbc-type="VARCHAR"/> <field name="street" persistence-modifier="persistent"> <field name="account" persistence-modifier="persistent"> </package>

47 Tractament de les relacions. Relacions 1 a N
En els dos cassos es pot especificar que s’utilitzi una taula per al join <package name="mydomain"> <class name="Account" identity-type="datastore"> <field name="firstName" persistence-modifier="persistent"> <column length="100" jdbc-type="VARCHAR"/> </field> <field name="lastName" persistence-modifier="persistent"> <field name="addresses" persistence-modifier="persistent"> <collection element-type=" mydomain.Address"/> <join/> </class> <class name="Address" identity-type="datastore"> <field name="city" persistence-modifier="persistent"> <column length="50" jdbc-type="VARCHAR"/> <field name="street" persistence-modifier="persistent"> </package>

48 Tractament de les relacions. Relacions M a N
Amb dues taules de join (amb Set): <package name="mydomain"> <class name="Product" identity-type="datastore"> <field name="name" persistence-modifier="persistent"> <column length=“50" jdbc-type="VARCHAR"/> </field> <field name="price" persistence-modifier="persistent"> <field name="suppliers" persistence-modifier="persistent"> <collection element-type="mydomain.Supplier"> <collection/> </class> <class name="Supplier" identity-type="datastore"> <column length=“100" jdbc-type="VARCHAR"/> <field name="products" persistence-modifier="persistent"> <collection element-type="mydomain.Product"> </package>

49 Tractament de les relacions. Relacions M a N
Amb només una taula de join (amb Set): <package name="mydomain"> <class name="Product" identity-type="datastore"> <field name="name" persistence-modifier="persistent"> <column length="50" jdbc-type="VARCHAR"/> </field> <field name="price" persistence-modifier="persistent"> <field name="suppliers" persistence-modifier="persistent" table="PRODUCTS_SUPPLIERS"> <collection element-type="mydomain.Supplier"/> <join> <column name="PRODUCT_ID"/> </join> <element> <column name="SUPPLIER_ID"/> </element> </class> <class name="Supplier" identity-type="datastore"> <column length="100" jdbc-type="VARCHAR"/> <field name="products" persistence-modifier="persistent" mapped-by="suppliers"> <collection element-type="mydomain.Product"/> </package>

50 Tractament de l’herència
També es pot configurar quina de les 3 estratègies que es van veure al tema “Disseny de la persistència. Introducció i mapping objecte/relacional” s’utilitzarà (només des de JDO 2.0) Exemple:

51 Estratègia new-table (per defecte)
<package name="store"> <class name="AbstractProduct"> <inheritance strategy="new-table"/> </class> <class name="Product" persistence-capable-superclass="store.AbstractProduct"> <class name="Book" persistence-capable-superclass="store.Product"> <class name="TravelGuide" persistence-capable-superclass="store.Book"> <class name="CompactDisc" persistence-capable-superclass="store.Product">

52 Estratègia subclass-table
<class name="AbstractProduct"> <inheritance strategy="subclass-table"/> </class> NOTA: Please note that JPOX doesn't currently support the use of classes defined with subclass-table strategy as being either the container end of a 1-N relationship, nor of such classes being the "element-type" in a 1-N relationship.

53 Estratègia superclass-table
<class name="Product"> <inheritance strategy="new-table"> <discriminator strategy="class-name"> <column name="PRODUCT_TYPE"/> </discriminator> </inheritance> </class> <class name="Book" persistence-capable-superclass="store.Product"> <inheritance strategy="superclass-table"/> <class name="TravelGuide" persistence-capable-superclass="store.Book"> <class name="CompactDisc" persistence-capable-superclass="store.Product"> ... Insereix el nom de la classe

54 Estratègia superclass-table (especificant el discriminador)
Insereix el nom que li especifiquem <class name="Product"> <inheritance strategy="new-table"> <discriminator strategy=“value-map“ value=“PRODUCT> <column name="PRODUCT_TYPE"/> </discriminator> </inheritance> </class> <class name="Book" persistence-capable-superclass="store.Product"> <inheritance strategy="superclass-table"> <discriminator value="BOOK"/> <class name="TravelGuide" persistence-capable-superclass="store.Book"> <discriminator value="TRAVELGUIDE"/> <class name="CompactDisc" persistence-capable-superclass="store.Product"> <discriminator value="COMPACTDISC"/> ...

55 Fitxer de metadades de l’exemple
<?xml version="1.0"?> <!DOCTYPE jdo PUBLIC "-//Sun Microsystems, Inc.//DTD Java Data Objects Metadata 2.0//EN" " <jdo> <package name="es2"> <class name="Persona"> <field name="grupp" persistence-modifier="persistent" /> <inheritance strategy="new-table"> <discriminator strategy="class-name"> <column name="tipus_persona"/> </discriminator> </inheritance> </class> <class name="Empleat" persistence-capable-superclass="es2.Persona"> <inheritance strategy="superclass-table"/> <class name="Grup"> <field name="persones" mapped-by="grupp"> <collection element-type="es2.Persona"/> </field> </package> </jdo>

56 Fitxer de propietats La connexió a la BD es fa mitjançant JDBC
El nom de la BD és prova La classe PersistenceManagerFactory en la implementació de JPOX és org.jpox.PersistenceManagerFactoryImpl javax.jdo.PersistenceManagerFactoryClass= org.jpox.PersistenceManagerFactoryImpl javax.jdo.option.ConnectionDriverName=com.mysql.jdbc.Driver javax.jdo.option.ConnectionURL=jdbc:mysql://localhost/prova javax.jdo.option.ConnectionUserName=login javax.jdo.option.ConnectionPassword=password

57 Definició de l’esquema de la BD
Si assignem el valor “true” a la propietat org.jpox.autoCreateSchema, JPOX crearà automàticament les taules a la BD, a partir del fitxer de les classes ehnanced i del fitxer de metadades, i també del fitxer de propietats (on estan les dades de connexió a la BD) També hi ha una eina per fer-ho expressament: java -cp "..." -Djavax.jdo.option.ConnectionDriverName= com.mysql.jdbc.Driver -Djavax.jdo.option.ConnectionURL= jdbc:mysql://localhost:3306/prova org.jpox.SchemaTool -create es2/package.jdo

58 Esquema generat (per a l’exemple)
mysql> show tables; | Tables_in_prova | | grup | | jpox_tables | | persona | 4 rows in set (0.00 sec)

59 Treballar amb un esquema existent
Si ja tenim la base de dades creada amb dades, també podem mapejar-ho amb les classes mitjançant el fitxer de metadades Exemple Taula PERSONAdb: CODIdb (clau primària), NOMdb, COGNOMdb Classe persona: nom, cognom Fitxer de metadades (pàg. següent)

60 Treballar amb un esquema existent
<?xml version="1.0"?> <!DOCTYPE jdo PUBLIC "-//Sun Microsystems, Inc.//DTD Java Data Objects Metadata 1.0//EN" " <jdo> <package name="es2"> <class name="Persona" identity-type="datastore" table="PERSONAdb"> <datastore-identity> <column name="CODIdb"/> </datastore-identity> <field name="nom"> <column name="NOMdb" length="255" jdbc-type="VARCHAR"/> </field> <field name="cognom"> <column name="COGNOMdb" length="255" </class> </package> </jdo>

61 Treballar amb un esquema existent
D’aquesta forma, no controlem els ids de les taules (ho fa el gestor) La clau primària ha de ser sobre una única columna, i ha de ser d’un tipus que es pugui mapejar a java.lang.Long (INT, INTEGER, SMALLINT...) Quan es fan insercions, poden haver problemes de duplicació de claus amb les ja existents Si cal, també es podria configurar per tenir-hi el control (vegeu documentació)

62 Datastore identity i claus primàries
També, des de JDO 2.0 (i JPOX 1.1) se pot assignar una certa “estratègia” a la generació d’identificadors Per exemple: <class name="Persona" identity-type="datastore"> <datastore-identity strategy="autoassign"/> ... </class> També es pot especificar quin és el atribut que es correspon amb la primary key (vegeu documentació)

63 Insercions package es2; import javax.jdo.JDOHelper;
import javax.jdo.PersistenceManager; import javax.jdo.PersistenceManagerFactory; import javax.jdo.Transaction; import java.util.Properties; public class Insercions { public static void main(String[] args) Properties props = new Properties(); props.setProperty("javax.jdo.PersistenceManagerFactoryClass", "org.jpox.PersistenceManagerFactoryImpl"); props.setProperty("javax.jdo.option.ConnectionDriverName", "com.mysql.jdbc.Driver"); props.setProperty("javax.jdo.option.ConnectionURL", "jdbc:mysql:///prova"); props.setProperty("org.jpox.autoCreateSchema","true"); PersistenceManagerFactory pmf = JDOHelper.getPersistenceManagerFactory(props); PersistenceManager pm = pmf.getPersistenceManager(); Transaction tx = pm.currentTransaction(); try { tx.begin(); Persona p1 = new Persona("pep", "garcia", 1970); Persona p2 = new Persona("josep", "fernandez", 1965); Empleat e1 = new Empleat("joan","sanchez",1975,1000); pm.makePersistent(p1); pm.makePersistent(p2); pm.makePersistent(e1); Grup g1 = new Grup("grup1"); g1.afegeixPersona(p1); g1.afegeixPersona(p2); g1.afegeixPersona(e1); Grup g2 = new Grup("grup2"); pm.makePersistent(g1); pm.makePersistent(g2); tx.commit(); } finally if (tx.isActive()) tx.rollback(); pm.close(); return;

64 Insercions des d’un JSP
page language="java" import="es2.*,javax.jdo.*,java.util.Properties" %> <html> <head><title>JSP Page</title></head> <body> <% PersistenceManager pm = pmf.getPersistenceManager(); Transaction tx = pm.currentTransaction(); try { tx.begin(); Persona p1 = new Persona("pep", "garcia", 1970); Persona p2 = new Persona("josep", "fernandez", 1965); Empleat e1 = new Empleat("joan","sanchez",1975,1000); pm.makePersistent(p1); pm.makePersistent(p2); pm.makePersistent(e1); Grup g1 = new Grup("grup1"); g1.afegeixPersona(p1); g1.afegeixPersona(p2); g1.afegeixPersona(e1); Grup g2 = new Grup("grup2"); pm.makePersistent(g1); pm.makePersistent(g2); tx.commit(); } finally out.println("entre en finally"); if (tx.isActive()) tx.rollback(); pm.close(); %> Insercions des d’un JSP <%! Properties props; PersistenceManagerFactory pmf; public void jspInit() { props = new Properties(); props.setProperty("javax.jdo.PersistenceManagerFactoryClass", "org.jpox.PersistenceManagerFactoryImpl"); props.setProperty("javax.jdo.option.ConnectionDriverName", "com.mysql.jdbc.Driver"); props.setProperty("javax.jdo.option.ConnectionURL", "jdbc:mysql://localhost:3306/prova"); props.setProperty("org.jpox.autoCreateSchema","true"); pmf = JDOHelper.getPersistenceManagerFactory(props); } %>

65 MakePersistentAll El mètode MakePersistentAll permet fer persistents un grup d’instàncies de cop: ... Persona p1 = new Persona("pep", "garcia", 1970); Persona p2 = new Persona("josep", "fernandez", 1965); Empleat e1 = new Empleat("joan","sanchez",1975,1000); Vector v = new Vector(); v.add(p1); v.add(p2); v.add(e1); pm.makePersistentAll(v);

66 Consulta tx.begin(); package es2;
Extent ext = pm.getExtent(Grup.class,false); Query query = pm.newQuery(ext,"nom==nomgrup"); query.declareParameters("String nomgrup"); Collection res = (Collection)query.execute("grup1"); Iterator it = res.iterator(); while (it.hasNext()) { Grup g1 = (Grup) it.next(); System.out.println(g1.getNom()); Set ps = g1.getPersones(); Iterator itp = ps.iterator(); while (itp.hasNext()) Persona p = (Persona)itp.next(); if (p instanceof Empleat) Empleat e = (Empleat) p; System.out.println(e.getNom()+ ". Salari: " + e.getSalari()); } else System.out.println(p.getNom()); query.close(res); tx.commit(); finally { if (tx.isActive()) tx.rollback(); pm.close(); return; package es2; import javax.jdo.JDOHelper; import javax.jdo.PersistenceManager; import javax.jdo.PersistenceManagerFactory; import javax.jdo.Transaction; import java.util.Properties; import javax.jdo.Extent; import javax.jdo.Query; import java.util.Iterator; import java.util.Set; import java.util.Collection; public class Consulta { public static void main(String[] args) { Properties props = new Properties(); props.setProperty("javax.jdo.PersistenceManagerFactoryClass", "org.jpox.PersistenceManagerFactoryImpl"); props.setProperty("javax.jdo.option.ConnectionDriverName", "com.mysql.jdbc.Driver"); props.setProperty("javax.jdo.option.ConnectionURL", "jdbc:mysql:///prova"); PersistenceManagerFactory pmf = JDOHelper.getPersistenceManagerFactory(props); PersistenceManager pm = pmf.getPersistenceManager(); Transaction tx = pm.currentTransaction(); try { Consulta

67 Sobre els Extents Un Extent identifica sobre quines instàncies s’ha de fer una consulta (filtre) Té informació sobre: La classe de les instàncies Si s’utilitzen subclasses d’ella Una col·lecció d’iteradors actius sobre l’Extent Per tant, no es fa cap acció quan es construeix un Extent, per exemple amb Extent ext = pm.getExtent(Grup.class,true); Les instàncies no es recuperen fins que se n’obté un iterador (amb totes les instàncies de la classe): Iterator it = extent.iterator(); O bé fins que s’executa una query sobre l’Extent: Query query = pm.newQuery(ext,"nom==nomgrup"); query.declareParameters("String nomgrup"); Collection res = (Collection)query.execute("grup1");

68 Més exemples de consultes
Consulta bàsica sobre un atribut: Empleats amb salari > Class empClasse = Empleat.class; Extent extEmpleat = pm.getExtent(empClasse, false); String filtre = “salari > 20000”; Query q=pm.newQuery(extEmpleat, filtre); Collection empleats = (Collection) q.execute ();

69 Més exemples de consultes
Consulta amb ordenació: Empleats amb salari > ordenats per ordre ascendent de salari Class empClasse = Empleat.class; Extent extEmpleat = pm.getExtent(empClasse, false); String filtre = “salari > 20000”; Query q=pm.newQuery(extEmpleat, filtre); q.setOrdering (“salari ascending”); Collection empleats = (Collection) q.execute ();

70 Més exemples de consultes
Consulta parametritzada: Empleats amb salari > paràmetre (20.000) Class empClasse = Empleat.class; Extent extEmpleat = pm.getExtent(empClasse, false); String filtre = “salari > sal”; String param = “Float sal”; Query q=pm.newQuery(extEmpleat, filtre); q.declareParameters(param); Collection empleats = (Collection)q.execute(new Float( ));

71 Més exemples de consultes
Consulta sobre un atribut amb referència única Persones del grup amb nom “grup1” Class persClasse = Persona.class; Extent extPersona = pm.getExtent(persClasse,true); String filtre = “grup.nom == nomGrup”; String param = “String nomGrup”; Query q=pm.newQuery(extPersona, filtre); q.declareParameters(param); Collection persones = (Collection)q.execute(new String(“grup1”));

72 Més exemples de consultes
Consulta sobre un atribut amb referència múltiple Grups que tenen almenys un empleat amb salari > paràmetre (20.000) Class grupClass = Grup.class; Extent extGrup = pm.getExtent (grupClass, false); String vars = “Empleat emp”; String filtre = “persones.contains(emp) && emp.salary > sal”; String param = “float sal”; Query q = pm.newQuery (extGrup, filtre); q.declareParameters (param); q.declareVariables (vars); Collection grups = (Collection) q.execute (new Float ( ));

73 JDO 2.0 (i per tant JPOX 1.1) permet definir les consultes en SQL:
Consultes SQL JDO 2.0 (i per tant JPOX 1.1) permet definir les consultes en SQL: Query query = pm.newQuery( "javax.jdo.query.SQL", "SELECT * FROM Persona"); query.setResultClass(Persona.class); List results = (List) query.execute(); Persona p = (Persona) result.iterator().next(); Problema: com gestionar l’herència?

74 Pool de connexions Es pot fàcilment configurar el gestor de persistencia perquè utilitzi un pool de connexions a la BD Propietat org.jpox.connectionPoolingType, que per defecte té el valor és “None” Per utilitzar DBCP: properties.setProperty( "org.jpox.connectionPoolingType", "DBCP");

75 Modificacions Si modifiquem un atribut d’una instància, aquest serà escrit automàticament a la BD quan es faci el commit Persistència transitiva o persistència per “abast” (reachability, alcance) Quan tenim una instància persistent que té com a atribut una referència a altre objecte que encara és temporal

76 Persistència transitiva o persistència per “abast”
Volem afegir un atribut adreca a Persona que sigui la seva adreça, i que serà una referència a una classe Adreca Si tenim una instància de Persona p que ja és persistent, quan creem una instància de Adreca a, encara és “transient” En el moment en què afegim la referència a la instància persistent amb un p.afegeixAddress(a); la instància es farà persistent en el moment en què es faci el commit, sense necessitat de fer el pm.makePersistent(a); En general, totes les referències que té una instància persistent, es faran també persistents amb el commit Noteu que és semblant al que passava amb Serialization Això ens permetrà escriure molt de codi sense fer constants crides a makePersistent

77 Exemple de persistència transitiva
Properties props = readProperties(“jdo.properties"); pmf = JDOhelper.getPersistenceManagerFactory(props); pm = pmf.getPersistenceManager(); tx = pm.currentTransaction(); tx.begin(); Persona p = new Persona(“toni”,”navarrete”,1973); Adreca a = new Address(“passeig circumval·lació 8”, “08003”, “Barcelona”, “Espanya”); p.afegeixAdreca(a); pm.makePersistent(p); /* p es marca com a persistent i també a, ja que p en conté la referència */ tx.commit();   // p i a són escrits a la BD pm.close();

78 Exemple de persistència transitiva
Properties props = readProperties(“jdo.properties"); pmf = JDOhelper.getPersistenceManagerFactory(props); pm = pmf.getPersistenceManager(); tx = pm.currentTransaction(); tx.begin(); Persona p = new Persona(“toni”,”navarrete”,1973); pm.makePersistent(p); // p es marca com a persistent tx.commit();   // p és escrit a la BD Adreca a = new Address(“passeig circumval·lació 8”, “08003”, “Barcelona”, “Espanya”); p.afegeixAdreca(a); // a es marca com a persistent tx.commit(); // a és escrit a la BD pm.close();

79 Eliminació d’instàncies
Dos mètodes del PersistenceManager: deletePersistent(instància) deletePersistentAll(col·lecció d’instàncies) L’eliminació no és transitiva! A diferència de makePersistent, s’ha de cridar a deletePersistent per a cada instància que s’ha d’eliminar

80 Estats d’una instància
Transient (fugaç, passatger) La instància s’ha creat però no se li ha comunicat al PersistenceManager Persistent-new Representa una instància que s’ha marcat com a persistent en la transacció actual Quan una instància transient és el paràmetre d’un makePersistent En aquest moment, el gestor li assigna un identificador JDO a la instància També es passen a persistent-new totes les instàncies “accessibles” des de la instància actual (persistència transitiva o per abast)

81 Estats d’una instància
Persistence-clean Les dades de la instància concideixen amb les guardades al magatzem de dades (això passa quan es fa el commit de la transacció activa) Altres: Persistent-dirty Fa referència a les instàncies que han canviat les seves dades en l’actual transacció (no coincideixen amb les dades del magatzem) Hollow (buit, hueco) La instància no conté totes les dades que hi ha al magatzem (això pot passar amb les consultes, típicament quan obtenim una instància i tanquem el gestor de persistència, es perden les referències) Persistent-deleted La instància es vol borrar amb un deletePersistent, però encara no s’ha fet el commit de la transacció activa

82 Mètodes del cicle de vida d’una instància
makePersistent makePersistentAll makeTransient makeTransientAll deletePersistent deletePersistentAll

83 Exemple d’estats d’instància
Properties props = readProperties(“jdo.properties"); pmf = JDOhelper.getPersistenceManagerFactory(props); pm = pmf.getPersistenceManager(); tx = pm.currentTransaction(); tx.begin(); Persona p = new Persona(“toni”,”navarrete”,1973); //la instància p és transient pm.makePersistent(p); //la instància p és persistent-new tx.commit();  //la instància p és persistent-clean Adreca a = new Adreca(“passeig circumval·lació 8”,  “08003”, “Barcelona”, “Espanya”); //la instància a és transient p.afegeixAdreca(a); //la instància a és persistent-new //la instància p és persistent-dirty tx.commit();  //les instàncies p i a són persistent-clean pm.close();

84 Accessos fora de transaccions
No es poden accedir als objectes fora de les transaccions Persona p; pm = pmf.getPersistenceManager(); tx = pm.currentTransaction(); try { tx.begin(); ... p = (Persona)it.next(); tx.commit();    } finally { tx.rollback(); } System.out.println(p.getNom.charAt(0));

85 Accessos fora de transaccions
Una forma simple per poder fer-ho s’ha de declarar la propietat NontransactionalRead a true: props.setProperty( "javax.jdo.option.NontransactionalRead", "true");

86 Atach/detach produeix una execpció NullPointerException
Quan el gestor de persistència (PersistenceManager) es tanca, els objectes que s’han obtingut amb ell queden en estat de hollow i no es pot accedir als seus atributs Per exemple (encara que la propietat NontransactionalRead sigui true): Persona p; pm = pmf.getPersistenceManager(); tx = pm.currentTransaction(); try { tx.begin(); ... p = (Persona)it.next(); tx.commit();    } finally { tx.rollback(); pm.close(); } System.out.println(p.getNom.charAt(0)); produeix una execpció NullPointerException

87 Atach/detach S’ha de separar (“detach”) l’objecte del graf abans de tancar el gestor: Cal definir la classe com a detachable al fitxer de metadades: <class name="Persona" detachable="true"> Cal separar l’objecte: Persona p; pm = pmf.getPersistenceManager(); tx = pm.currentTransaction(); try { tx.begin(); ... Persona p2 = (Persona)it.next(); p = (Persona)pm.detachCopy(p2); tx.commit();    } finally { tx.rollback(); pm.close(); } System.out.println(p.getNom.charAt(0));

88 Atach/detach En el cas de col·leccions: Collection persones;
PersistenceManager pm=getPersistenceManager(); Transaction tx=pm.currentTransaction(); try { tx.begin(); Query q = pm.newQuery(Persona.class); Collection query_persones=q.execute(); persones = pm.detachCopyAll(query_persones); tx.commit(); } ...

89 Atach/detach Si després s’hagués de tornar d’incloure al graph:
Persona p; pm = pmf.getPersistenceManager(); tx = pm.currentTransaction(); try { tx.begin(); ... Persona p2 = (Persona)it.next(); p = (Persona)pm.detachCopy(p2); tx.commit();   // p és escrit a la BD } p.setNom("toni"); tx = pm.currentTransaction(); pm.attachCopy(p,true); tx.commit();

90 Atach/detach Però el “detach” no és transitiu. Això donarà error:
Persona p; pm = pmf.getPersistenceManager(); tx = pm.currentTransaction(); try { tx.begin(); ... Persona p2 = (Persona)it.next(); p = (Persona)pm.detachCopy(p2); tx.commit();    } finally { tx.rollback(); pm.close(); } System.out.println(p.getAdreca.getNomCarrer());

91 Per defecte, només es recuperen els següents atributs:
Fetch groups Per defecte, només es recuperen els següents atributs: primitius : boolean, byte, char, double, float, int, long, short Classes de tipus primitius: Boolean, Byte, Character, Double, Float, Integer, Long, Short java.lang.String, java.lang.Number java.math.BigDecimal, java.math.BigInteger java.util.Date

92 I després s’especifica que el gestor utililitzarà aquest fetch-group:
Fetch groups Per modificar aquest comportament per defecte s’ha de definir un “fetch group” propi: <class name="Persona" detachable="true"> ... <field name="adreca" persistence-modifier="persistent"/> <fetch-group name="detach_persona_adreca"> <field name="adreca"/> </fetch-group> </class> I després s’especifica que el gestor utililitzarà aquest fetch-group: pm.getFetchPlan().addGroup("detach_persona_adreca");

93 Fetch groups Persona p; pm = pmf.getPersistenceManager();
tx = pm.currentTransaction(); try { tx.begin(); pm.getFetchPlan().addGroup("detach_persona_adreca"); ... Persona p2 = (Persona)it.next(); p = (Persona)pm.detachCopy(p2); tx.commit();    } finally { tx.rollback(); pm.close(); } System.out.println(p.getAdreca.getNomCarrer());

94 Adreces JDO http://java.sun.com/products/jdo http://www.jpox.org
O (JSR-12) (website de JPOX) (molts de recursos sobre JDO) (canal sobre persistència de JavaWorld)


Descargar ppt "Disseny de la persistència JDO i frameworks de persistència"

Presentaciones similares


Anuncios Google