230 likes | 360 Views
Disseny de la persistència Hibernate i frameworks de persistència POJO. Toni Navarrete Enginyeria del Software II – UPF 200 7. Recordatori: problemes (i aventatges) d’altres solucions. Serialitzatió Avantantges: Estàndard en qualsevol ambient Java Fàcil d’utilitzar
E N D
Disseny de la persistència Hibernate i frameworks de persistència POJO Toni Navarrete Enginyeria del Software II – UPF 2007
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
Recordatori: problemes (i aventatges) d’altres solucions • JDBC • Permet treballar amb un Gestor de BD • Dóna accés a SQL • Usa el model relacional • 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, referides a l’esquema de la BD • SQL no està realment estandaritzat, amb la qual cosa la portabilitat no sempre és total
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 • Si cal canviar l’esquema de la BD també cal canviar les classes • El resultat sol ser que s’escriu codi Java procedural per manipular les taules. No OO
Recordatori: problemes (i aventatges) d’altres solucions • EJB 2.1 i la persistència manegada pel contenidor (CMP) • Defineix un mecanisme de persistència transparent • Els mètodes dels EJB d’entitat són independents de l’esquema de dades • Llenguatge de consultes abstracte, independent de SQL • EJB és una arquitectura complexa i amb un alt overhead
Objectius dels frameworks de persistència POJO (Plain Old Java Object) • Treballar amb el model de classes i deixar al framework de persistència la traducció al model relacional • Normalment el mapping s’especifica mitjançant un fitxer XML • Operacions d’accés a la BD referides a: • Guardar objectes (inserts) • Modificar objectes (updates) • Eliminar objectes (deletes) • Recuperar col·leccions d’objectes (selects) • Independència entre el model de classes i el model físic de la BD mínima intrusió i màxima transparència
Hibernate • Hibernate és un d’aquests frameworks de persistència POJO • Codi obert i gratuït (llicència GNU LGPL) • Molt estès, gran comunitat de desenvolupadors i usuaris
Problemes dels frameworks de persistència • Adoptar un API no estandaritzada é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 del framework
JDO • És una iniciativa de la comunitat Java per crear un framework estandaritzat per a persistència (de la mateixa forma 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) • JPOX és la implementació de referència (i lliure), però no és prou estable • JDO pot suportar no només BD relacionals sinó qualsevol forma d’emmagatzemantge permanent (XML, fitxers,...) • És molt “transparent” (per exemple, persistència transitiva) • No ha acabat de consolidar-se com a estàndard • Actualment un projecte Apache: http://db.apache.org/jdo/
Java Persistence API (JPA) • Definida en EJB 3.0 (JavaEE 5) http://java.sun.com/javaee/technologies/persistence.jsp • La idea original era que JPA es fes a partir de JDO, però ha acabat essent una especificació diferent • http://db.apache.org/jdo/jdo_v_jpa.html • http://db.apache.org/jdo/jdo_v_jpa_orm.html • JPA substitueix als EJB d’entitat • Ja no cal definir les interfícies • No s’utilitza el deployment descriptor
Hibernate i els estàndards • Hibernate no té cap relació amb JDO • Té una API “EntityManager” per permetre compatibilitat amb Java Persistenca API
Nota: Hibernate i JDBC • Hibernate no substitueix JDBC • Són complementaris • Hibernate utilitza 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 SGBD
Exemple d’una petita aplicació amb Hibernate • Farem una classe que permet guardar a la BD instàncies d’una classe Persona • Una altra classe ens permetrà recuperar les instàncies de Persona a la BD
La classe Persona package persones; public class Persona { Long id; //a Hibernate cal definir un identificador d’instància, amb els seus mètodes get i set String nom, cognom; int anyNaixement = 0; public Persona() {} // a Hibernate é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 Long getId() { return id; } private void setId(Long id) { this.id = id; } 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; } }
Mapeig entre classe i taula(es) de la BD • Fitxer persona.hbm.xml <?xml version="1.0"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"> <hibernate-mapping package="persones"> <class name="Persona" table="PERSONA"> <id name="id" column="PERSONA_ID"> <generator class="native"/> </id> <property name="nom"/> <property name="cognom"/> <property name="anyNaixement"/> </class> </hibernate-mapping>
Configuració del gestor de BD (i altres propietats) <?xml version='1.0' encoding='utf-8'?> <!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd"> <hibernate-configuration> <session-factory> <!-- Propietats de la BD --> <property name="connection.driver_class">com.mysql.jdbc.Driver</property> <property name="connection.url">jdbc:mysql://localhost:3306/hibernate_db1 </property> <property name="connection.username">usuari</property> <property name="connection.password">password</property> <!-- JDBC connection pool (use the built-in) --> <property name="connection.pool_size">1</property> <!-- SQL dialect --> <property name="dialect">org.hibernate.dialect.MySQLDialect</property> • Fitxer hibernate.cfg.xml
Configuració del gestor de BD (i altres propietats) • Fitxer hibernate.cfg.xml <!-- Enable Hibernate's automatic session context management --> <property name="current_session_context_class">thread</property> <!-- Disable the second-level cache --> <property name="cache.provider_class">org.hibernate.cache.NoCacheProvider</property> <!-- Echo all executed SQL to stdout --> <property name="show_sql">true</property> <!-- Esborra i torna a crear l’esquema de la BD a cada execució (només per proves) --> <!-- Cal comentar-ho quan volguem fer consultes!!!--> <property name="hbm2ddl.auto">create</property> <!-- Referència al(s) fitxer(s) de mapping --> <mapping resource="persones/Persona.hbm.xml"/> </session-factory> </hibernate-configuration>
package persones; import org.hibernate.*; import org.hibernate.cfg.*; public class Insercions { public static void main(String[] args) { try { // Crea la Session de hibernate a partir del fitxer hibernate.cfg.xml SessionFactory sessionFactory = new Configuration().configure().buildSessionFactory(); Session session = sessionFactory.getCurrentSession(); //comença la transacció session.beginTransaction(); //crea les instàncies que calgui i les guarda Persona p1 = new Persona("pep", "garcia", 1970); Persona p2 = new Persona("josep", "fernandez", 1965); session.save(p1); session.save(p2); //fa el commit de la transacció session.getTransaction().commit(); //tanca el sessionFactory i allibera els recursos associats (caches, pools,…) sessionFactory.close(); } catch (Throwable ex) { System.err.println("Initial SessionFactory creation failed." + ex); throw new ExceptionInInitializerError(ex); } } } Inserció d’instàncies
package persones; import org.hibernate.*; import org.hibernate.cfg.*; public class Consulta { public static void main(String[] args) { try { // Crea la Session de hibernate a partir del fitxer hibernate.cfg.xml SessionFactory sessionFactory = new Configuration().configure().buildSessionFactory(); Session session = sessionFactory.getCurrentSession(); //comença la transacció session.beginTransaction(); //recupera les instàncies de la classe Persona i escriu els seus atributs per pantalla java.util.List persones = session.createQuery("from Persona").list(); while (persones.listIterator().hasNext()) { Persona p = (Persona)persones.listIterator().next(); System.out.println("Nom: "+p.getNom()); System.out.println("Cognom: "+p.getCognom()); System.out.println("Any naixement: "+p.getAnyNaixement()); } //fa el commit de la transacció session.getTransaction().commit(); // tanca el sessionFactory i allibera els recursos associats (caches, pools,…) // sessionFactory.close(); } catch (Exception e) { e.printStackTrace(); } } } Consulta d’instàncies
package persones; import org.hibernate.*; import org.hibernate.cfg.*; public class Modificacio { public static void main(String[] args) { try { // Crea la Session de hibernate a partir del fitxer hibernate.cfg.xml SessionFactory sessionFactory = new Configuration().configure().buildSessionFactory(); Session session = sessionFactory.getCurrentSession(); //comença la transacció session.beginTransaction(); //recupera les instàncies de la classe Persona java.util.List persones = session.createQuery("from Persona").list(); while (persones.listIterator().hasNext()) { Persona p = (Persona)persones.listIterator().next(); if (p.getNom().equals("pep")) p.setNom("josep"); } //fa el commit de la transacció session.getTransaction().commit(); // tanca el sessionFactory i allibera els recursos associats (caches, pools,…) // sessionFactory.close(); } catch (Exception e) { e.printStackTrace(); } } } Modificació d’instàncies
package persones; import org.hibernate.*; import org.hibernate.cfg.*; public class Esborrat { public static void main(String[] args) { try { // Crea la Session de hibernate a partir del fitxer hibernate.cfg.xml SessionFactory sessionFactory = new Configuration().configure().buildSessionFactory(); Session session = sessionFactory.getCurrentSession(); //comença la transacció session.beginTransaction(); //recupera les instàncies de la classe Persona i escriu els seus atributs per pantalla java.util.List persones = session.createQuery("from Persona").list(); while (persones.listIterator().hasNext()) { Persona p = (Persona)persones.listIterator().next(); if (p.getAnyNaixement()<1970) session.delete(p); } //fa el commit de la transacció session.getTransaction().commit(); // tanca el sessionFactory i allibera els recursos associats (caches, pools,…) // sessionFactory.close(); } catch (Exception e) { e.printStackTrace(); } } } Esborrat d’instàncies