MOTORES DE PERSISTENCIA DE OBJETOS EN

Anuncio
MOTORES DE PERSISTENCIA DE OBJETOS EN BASE DE DATOS RELACIONALES.
Fernando Boiero, Laura Castelli, Leandro Coschiza y Paulo Schiavi.
Alumnos de la cátedra de Proyecto Final, carrera de Ingeniería en Sistemas de Información,
Facultad Regional Villa María, Universidad Tecnológica Nacional. Av. Universidad 450, Villa María,
X5900GLB, Cba. – e-mail: [email protected]
Tutores: Ing. Zohil Julio Cesar - Mg. Juan Vanzetti
Introducción
El común de las aplicaciones que permiten almacenar y recuperar información necesitan de
alguna interacción con una base de datos relacional. Esto ha representado un problema para los
desarrolladores porque el diseño de datos relacionales y los ejemplares orientados a objetos
comparten estructuras de relaciones muy diferentes dentro de sus respectivos entornos.
Las bases de datos relacionales poseen una configuración tabular y los ambientes orientados a
objetos normalmente están relacionados en forma de árbol. Esta 'diferencia de impedancia' ha
llevado a los desarrolladores a intentar construir un puente entre el mundo relacional y el mundo
orientado a objetos.
De acuerdo a lo estudiado en diferentes asignaturas que componen la carrera de Ingeniería en
Sistemas de Información, se observa que las opciones basadas en imponer un único formato de
datos a toda la aplicación presentan algunos inconvenientes. En el caso de que toda la aplicación
siga el modelo relacional, se pierden las ventajas del paradigma objeto. En cambio si la aplicación
sigue únicamente el modelo orientado a objetos, se tiene que emplear repositorios de objetos. En
la actualidad dichos repositorios son tecnologías inmaduras y tienen un bajo nivel de
estandarización. Si la aplicación está programada en un lenguaje orientado a objetos y la
persistencia se realiza con una base de datos relacional, se tiene que especificar un puente que
permita la comunicación conjunta, simple, transparente y eficiente entre estos dos modelos [4].
Este puente o traductor entre los dos formatos no es más que un componente de software
(específicamente, una capa de programación), a la que se le dan los nombres de “capa de
persistencia”, “capa de datos”, “correspondencia O/R” (“OR mapping”) o “motor de persistencia”
[2].
En este trabajo, se comparan dos de las tecnologías de persistencia de objetos Java Persistent
Objects (JPOX) e Hibernate) que intentan simplificar la tarea de conectar el lenguaje de
programación orientado a objetos Java con bases de datos relacionales.
Metodología
La investigación se elaboró en tres etapas. En la primera, se describe teóricamente las dos
tecnologías. En la segunda etapa, se implementan aplicaciones simples con el propósito de
testear el funcionamiento de las dos tecnologías de mapeo expuestas. Por último, se exponen los
resultados obtenidos.
Descripción teórica
Hibernate
Es una implementación del API de Persistencia de Java (JPA). Una de las características que
distingue al Hibernate es que los desarrolladores no tienen que implementar interfaces
propietarias o extender clases bases propietarias para poder persistir las clases. Hibernate trata
con el API reflection de Java y el aumento de clases en tiempo de ejecución utilizando una librería
de generación de código Java de alto rendimiento, llamada CGLIB. La misma se utiliza para
extender clases e implementar interfaces en tiempo de ejecución [1].
A continuación se detallan los pasos necesarios para la implementación de un programa que
utiliza Hibernate [3] [4]:
•
En primer lugar, se deben agregar las librerías del framework al proyecto (antlr.jar,
cglib.jar,asm.jar,
asm-attrs.jar,
commons-collections.jar,
commons-logging.jar,
hibernate3.jar, jta.jar, dom4j.jar, ehcache.jar, c3po.jar).
•
Posteriormente, se debe definir la configuración global del Session Factory de
Hibernate mediante un archivo XML(hibernate.cfg.xml), o se puede pasar esta
parametrización desde la aplicación. En la misma se definen los siguientes datos:
a. Definición de la base de datos y su forma de conexión:
i. Dialecto para interactuar con el motor de BD.
ii. Driver JDBC que utilizaremos para conectarnos.
iii. Usuario, clave, URL de conexión y base de datos a la cual se va a
conectar.
b. Forma de administrar el pool de conexiones y sesiones simultáneas por la
aplicación a la base de datos.
c. Forma de mapeo.
i. En el caso de utilizar XML, usando patrones de persistencia, se define
cómo cada atributo y relación de las clases se convierten en registros de
una base de datos relacional.
ii. En el caso de utilizar anotaciones, se tiene que agregar comentarios
especiales dentro del código fuente especificando, al igual que el caso
anterior, cómo persistir los objetos.
•
Luego, se debe instanciar con la configuración anteriormente detallada Session
Factory de Hibernate.
•
Por último, a la instancia anterior se le solicita una sesión para poder persistir o
consultar los objetos cuando sea necesario. Existen dos formas de realizar dichas
consultas:
a. Hibernate Query Languaje(HQL): es un lenguaje de consultas similar a SQL
pero no se pregunta por registros y tablas, sino que se consulta por objetos.
b. Criteria: esta interfaz permite especificar consultas a lo largo del desarrollo del
programa (en base a clases y métodos de las mismas) sobre las entidades
definiendo un conjunto de restricciones. El uso de Criteria puede ser muy
conveniente cuando se tienen que componer consultas de forma dinámica.
Java Persistent Objects (JPOX)
JPOX fue lanzado al mercado en el año 2003, siendo éste una implementación de JDO1 para
RDBMS. En la versión más reciente de JPOX (1.2.2) soporta JDO, JPA, RDBMS y db4o. Debido a
los cambios en la dirección de JPOX desde 24/04/2008, se lo denomina DataNucleus.
El uso de JPOX se divide en los siguientes pasos [7]:
•
En primer lugar se deben agregar las librerías del framework al proyecto (gdo.jar,
JPOX.jar, log4j.jar)
•
En segundo lugar, se debe setear la configuración global de la persistencia en un
objeto de tipo Properties.
•
Posteriormente, mediante anotaciones o XML se crean los mapeos de las distintas
clases
•
En cuarto lugar se crea un objeto PersistenceManagerFactory. El mismo sirve para
administrar la persistencia de los objetos sobre la base de datos.
•
Por último, usando la instancia PersistenceManagerFactory se crean transacciones,
guardando o recuperando objetos sobre la base de datos. Para recuperar los objetos
se puede usar el lenguaje de consultas JDOQL.
Implementación de Aplicaciones Simples
Para testear las tres opciones se utilizará el diagrama de clases de la figura 1:
Provincia
-nombre
-pais
-cuidades
+getNombre()
+setNombre()
+getPais()
+setPais()
+getCiudades()
+setCiudades()
1
*
1
*
País
-nombre
-provincias
+getNombre()
+setNombre()
+getProvincias()
+setProvincias()
Ciudad
-nombre
-provincia
+getNombre()
+setNombre()
+getProvincia()
+setProvincia()
Figura 1: Diagrama de clases del test.
Para realizar el ejemplo se utilizará la clase Provincia, agregándole un atributo id y sus
respectivas anotaciones para que pueda persistir en la base de datos.
@Entity
@Table(name="provincia")
public class Provincia {
public Provincia (){ }
@Id @GeneratedValue(strategy=javax.persistence.GenerationType.IDENTITY)
private Long id;
private String nombre;
@ManyToOne
private Pais pais;
@OneToMany(mappedBy="ciudad")
private Set<Ciudad> ciudades=new HashSet(0);
public String getNombre() { return nombre; }
public void setNombre(String nuevoNombre) {
this.nombre = nuevoNombre;
}
public Pais getPais() {
return pais;
}
public void setPais(Pais nuevoPais) {
this.pais = nuevoPais;
}
public String toString()
{
return nombre ;
}
public int compareTo(Object x) {
Ciudad p = ( Ciudad) x;
return nombre.compareTo(p.getNombre());
}
public boolean equals(Object obj) {
if(obj == null) return false;
Ciudad p = ( Ciudad)obj;
if(nombre.compareTo(p.getNombre())==0) return true;
else return false;
}
public int hashCode() {
return nombre.hashCode();
} }
Para implementar este ejemplo se emplea como motor de base de datos MySQL. La base de
datos se llamará “ejemplo”, el usuario para accederla se denominará “root” y la contraseña
“ninguna” [5] [6].
Implementación de Hibernate
AnnotationConfiguration conf = new AnnotationConfiguration();
conf.setProperty("hibernate.connection.driver_class","com.mysql.jdbc.Driver");
conf.setProperty("hibernate.dialect","org.hibernate.dialect.MySQLDialect");
conf.setProperty("hibernate.connection.url","jdbc:mysql://localhost/ejemplo");
conf.setProperty("hibernate.connection.username","root");
conf.setProperty("hibernate.connection.password","ninguna");;
conf.addAnnotatedClass(Pais.class);
conf.addAnnotatedClass(Provincia.class);
conf.addAnnotatedClass(Ciudad.class);
SessionFactory sessionFactory = conf.buildSessionFactory();
Session session= sessionFactory.openSession();
Pais p = new Pais();
p.setNombre("Argentina");
Transaction tx = session.beginTransaction();
session.save(p);
tx.commit();
Criteria criterio=session.createCriteria(Provincia.class)
.add(Restrictions.like("nombre","Córdoba"));
List listado= criterio.list();
Implementación de JPOX
Primero hay que crear JPOX.properties donde se definen los contextos de persistencia de la
aplicación.
javax.jdo.PersistenceManagerFactoryClass=org.JPOX.jdo.JDOPersistenceManagerFactory
javax.jdo.option.ConnectionDriverName=com.mysql.jdbc.Driver
javax.jdo.option.ConnectionURL=jdbc:mysql://localhost/ejemplo
javax.jdo.option.ConnectionUserName=root
javax.jdo.option.ConnectionPassword=ninguna
org.JPOX.autoCreateSchema=true
org.JPOX.validateTables=false
org.JPOX.validateConstraints=false
Desde la aplicación se implementa como se detalla el siguiente ejemplo:
PersistenceManagerFactory pmf =
JDOHelper.getPersistenceManagerFactory("JPOX.properties");
PersistenceManager pm = pmf.getPersistenceManager();
Transaction tx=pm.currentTransaction();
tx.begin();
Pais p = new Pais();
p.setNombre("Argentina");
pm.makePersistent(p);
tx.commit();
Query q = pm.newQuery(Provincia.class, "nombre == \" Córdoba\");
List listado=(List)q.execute();
Conclusiones
Luego de desarrollar las dos implementaciones, se derivan las siguientes conclusiones, las
cuales fueron plasmadas en la tabla que se muestra a continuación.
Tabla 1: Resumen comparativo.
Simplicidad
Flexibilidad
Portabilidad
Performance
Estándares
Curva de aprendizaje y
soporte
Recuperación de objetos
Hibernate
Muy simple
Media
Media
Muy buena
Implementa JPA
Baja
JPOX
Muy Simple
Alta
Media
Muy buena
Implementa JDO y JPA
Media
Por objetos simples, consulta
con HQL y el API Criteria
Por objetos simples y consulta
con JDOQL
Cabe destacar que el aspecto analizado Simplicidad se ha medido en líneas de código. En los
casos de estudio se obtuvo que para Hibernate se emplearon 17 líneas de código y en cambio
para JPOX sólo 18.
La portabilidad para ambas opciones es media, debido a que se necesitan agregar algunas
librerías al kit de desarrollo estándar para java de la Sun.
Al analizar el parámetro Performance se advierte que existen demasiados factores que inciden
en forma determinante al momento de ponderar los casos de pruebas. Como por ejemplo: driver
de base de datos, indexación de la misma y tipos de objetos. Tomando como base el benchmarks
publicado en http://www.devx.com/Java/Article/33768/0/page/4 Hibernate demoró 360 ms para
crear y registrar 100 objetos simples contra 560 ms de JPOX y para leer 100 objetos simples
Hibernate demoró 295 ms contra 325 ms de JPOX [9].
Se considera que es difícil cuantificar el análisis de la curva de aprendizaje y el soporte, dado
que encierran numerosos aspectos subjetivos. En ambos casos se poseen páginas oficiales no
sólo con la documentación sino también con ejemplos didácticos que ayudan a su rápida
implementación. Hibernate en términos de soporte es más estable debido a que lleva muchos
años en el mercado siendo una de las comunidades Open Source con miembros muy activos.
Desde el punto de vista de su utilización, se percibe a través de los ejemplos dados anteriormente
que los pasos y formas de uso son muy similares, por lo que se concluye que el tiempo de
aprendizaje entre ambas es muy similar [9].
En vista de estos resultados, para un desarrollador junior que desea persistir sus objetos, se
recomienda utilizar Hibernate, debido a su simplicidad, disponibilidad de información y su alta
aplicación en la industria.
Agradecimientos
Se agradece la colaboración del Ing. Zohil Julio Cesar y Mg. Juan Vanzetti quienes contribuyeron
al desarrollo del mismo. Un agradecimiento especial a Mariano Turcutto.
Referencias
[1] Introducción a Hibernate - Francesc Roses Albial - Octubre de 2004
[2] Apunte de Motores de Persistencia - Dr. Vincent Ramon Palasillana - Director Académico Universidad Francisco Gaviria
[3] Persistencia de Objetos utilizando Hibernate - Jeff Hanson - (www.deux.com/java )
[4] Persistencia de Objetos Java: El camino hacia Hibernate - Michael Glogls (www.goegl.de )
[5] www.javahispano.org - (tutoriales, foros y ejemplos)
[6] http://www.adictosaltrabajo.com - (tutoriales y ejemplos)
[7] http://JPOX.org - (Glosario y definiciones)
[8] http://wikiipedia.com - (Glosario y definiciones)
[9] http://www.devx.com/Java/ (artículos y ejemplos)
Glosario
Bean: Clase simple programada de manera encapsulada en el lenguaje JAVA. Debe implementar
Serializable y tener un constructor por defecto. [8]
Criteria: API de Hibernate para recuperar objetos de la base de datos que permite ir agregando
filtros de manera simple y escalonada. [8]
JPA: Java Persistence API, API de persistencia desarrollada para la plataforma Java EE e incluida
en el estándar EJB3. [8]
Descargar