Persistencia con HibernatePersistencia con Hibernate
I i d l P iIngeniera de la ProgramacinPrctica 8 2009/2010
ndice
Parte 1: Introduccin a Hibernate. Persistencia de objetos con BD relacionales Persistencia de objetos con BD relacionales Persistencia con BD relacionales + mapping objeto relacional. Visin general de Hibernate. Comprobacin de configuracin en Eclipse Comprobacin de configuracin en Eclipse. Creacin de un proyecto ejemplo.
Parte 2: Visin detallada de Hibernate.b d b Obtencin de objetos persistentes.
Lenguaje HQL (Hibernate Query Language). Query. Archivos de Mapping. Hibernate Console. Tools Hibernate. Ejemplo guiado.
2
Persistencia de objetos con BD relacionales
Persistencia: es el mecanismo que permite almacenar datos desde memoria de modo que puedan ser recuperados cuando la memoria de modo que puedan ser recuperados cuando la aplicacin se ejecuta de nuevo.
La mayor parte de las aplicaciones comerciales utilizan un gestor de base de datos relacional (GBDR) y un lenguaje de de base de datos relacional (GBDR) y un lenguaje de programacin orientado a objeto.
Los objetos deben ser convertidos en tuplas de tablas y a la inversainversa.
Las aplicaciones utilizan normalmente sentencias SQL embebidas en un lenguaje de programacin OO.
3
BD relacionales + mapping objeto relacional (1)
El objetivo es disponer de un marco transparente de persistenciapersistencia.
El programador trabajar con objetos no con sentencias SQL.
Los objetos modificados sern salvados de forma transparente en la base de datos.
La correspondencia de objetos a tablas se define La correspondencia de objetos a tablas se define habitualmente en archivos XML.
4
BD relacionales + mapping objeto relacional (2)
Marcos de persistencia: Java Data Objects (JDO). Container Managed Persistence (CMP) dentro
de Enterprise JavaBeans (EJB) de Sun. Hibernate (Open-Source).
5
Visin general de Hibernate
Hibernate es una solucin para gestionar de manera transparente g pla persistencia en entornos orientados a objeto.
Permite en tiempo de ejecucin transformar objetos en tuplas y tuplas en objetos.
Solucin independiente de la BD utilizadautilizada.
Utiliza archivos XML: Para definir la transformacin de
clases a tablas (archivos de (mapping).
Para indicar qu base de datos se utilizar (archivo de configuracin)configuracin)
6
Visin general de Hibernate: arquitectura
Arquitectura:
7
Visin general de Hibernate:arquitectura
Session: Es un concepto entre la conexin y transaccin. Puede entenderse como el conjunto de objetos cargados Puede entenderse como el conjunto de objetos cargados relacionados con una unidad de trabajo. No es thread-safe. No permite concurrencia. Est pensado a ser usado por un
l th d i lt tsolo thread simultneamente. SessionFactory: Es una factora de sesiones. Proporciona
objetos Session. Es thread-safe. Permite concurrencia.j Configuration: Encargado de cargar los ficheros de mapping,
las propiedades especficas de Hibernate y entonces crear el SessionFactorySessionFactory
Transaction: Es opcional. Abstrae del modelo transaccional subyacente: JDBC, JTA UserTransaction, CORBA
8
Visin general de Hibernate: estructura de las clases persistentes
Para que una clase pueda ser
public class Mensaje {private int id;
pueda ser persistente debe tener:
private String text;private Mensaje SiguienteMensaje;Mensaje() {}public Mensaje(String text) {
this.text = text;}
Constructor por defecto.
Mtodos getXXX,
}public int getId() {
return id;}@SuppressWarnings("unused")private void setId(int id) {
thi id idMtodos getXXX, setXXX para cada atributo.
Un atributo que acte id ifi d
this.id = id;}public String getText() {
return text;}public void setText(String text) {
como identificador. this.text = text;}public Mensaje getSiguienteMensaje() {
return SiguienteMensaje;}public void setSiguienteMensaje(Mensajepublic void setSiguienteMensaje(Mensaje SiguienteMensaje) {
this.SiguienteMensaje = SiguienteMensaje;}
}
9
Visin general de Hibernate: mappings
Los archivos de mapping definen cmo se transforman las clases del modelo en tablas, en particular: Equivalencia atributo columna. Cmo se generan las claves primarias, para
las inserciones de registros (generator class). Cmo se relacionan mediante claves ajenas
con otras tablas.
10
Estructura del Mapping
name="id" column="ID_MENSAJE" type = "integer">
Mapping de relaciones
11
Archivo de configuracin
org hsqldb jdbcDrivername= hibernate.connection.driver_class >org.hsqldb.jdbcDriverjdbc:hsqldb:hsql://localhost/mensajessa
Configuracin de la conexin
org.hibernate.dialect.HSQLDialect
Variante de SQL
Configuracin de la conexinJDBC
Archivos de mapping
Variante de SQL
/ g
12
Interface Session
La interfaz Session permite recuperar y almacenar objetos en la base de datos a travs de una comunicacin con el en la base de datos a travs de una comunicacin con el motor de Hibernate.
Un objeto sesin se obtiene de una factora de sesiones: Un objeto sesin se obtiene de una factora de sesiones:sesion = UtilidadHibernate.getSessionFactory().openSession();
Proporciona una cach (contexto de persistencia) que evita interacciones innecesarias con la base de datos. Cuando ejecutamos las operaciones: find(), update(), save(), j p psaveOrUpdate(), get(), delete() o cualquier otra operacin de la interfaz Session, estamos interactuando de manera transparente con la cach de Hibernate. Las operaciones no se realizan directamente sobre la base de datos se almacenan en la cach.
13
Interface Session: Ciclo de vida de persistencia
El estado de los objetos est relacionado con el contexto de persistencia (i.e con una sesin).( )
Dentro de la aplicacin el ciclo de vida de los objetos con respecto a la persistencia tiene los siguientes estados:p g
Transitorio o voltil (transient): La instancia no est asociada con un contexto de persistencia.
Persistente (persistent): Asociado con un contexto de persistencia.Sepa ado o independiente (detached) La instancia estaba asociada con n Separado o independiente (detached): La instancia estaba asociada con un contexto de persistencia que ha sido cerrado.
14
Interface Session: Ciclo de vida de persistencia
El diagrama muestra los estados de un objeto en una aplicacin Hibernate.
15
Interface Session: OperacionesMensaje Mensaje = new Mensaje("Hola a
todo(a)s, primer mensaje.");sesion.save(Mensaje);
Hacer persistente un objetotransitorio.
sesion.save(Mensaje);
Mensaje mensaje = (Mensaje) sesion.get(Mensaje.class, ID);
Obtener un objeto si se sabeque existe. g ( j , );
Mensaje mensaje = (Mensaje) terceraSession.load(Mensaje.class, ID);
q
Obtener un objeto si no se estseguro de que existe.
sesion.delete(mensaje);
sesion.update(mensaje);
Borrar un objeto
Actualizar
sesion.saveOrupdate(mensaje);
Actualizar
Salvar o actualizar
Sesion.flush()Sincronizar el contexto de persistencia con la BD.
16
Transacin
Una transaccin es un conjunto de operaciones sobre unabase de datos que terminan en un commit (xito) o bien en base de datos que terminan en un commit (xito) o bien en un rollback (fallo).
Inicio de transaccinInicio de transaccin
Operacin A: INSERT INTO..
Operacin B: INSERT INTO..
Rollback(Error)
(xito)
Commit
( to)
17
Transacciones en Hibernate
El patrn comn es utilizar unasesin por transaccin.p
Sesion = UtilidadHibernate.getSessionFactory().
Obtener una sesin de Hibernate
openSession();Transaction tx = Sesion.beginTransaction();
try {
Iniciar una nueva transaccin
Sesion.save(Mensaje);tx.commit();
} catch( RuntimeException e){
Ejecutar operaciones Hibernate con la BD
Commit transaccin if (tx != null) { tx.rollback(); throw e; }
}Cerrar Sesin
Commit transaccin
finally { Sesion.close();}
18
Visin general de Hibernate: generadores
Los generadores de clave pueden ser de los siguientes tipos:G d D i iGenerador Descripcin
native Usa identity, sequence o hilo en funcin del SGDB residenteresidente
identity Soportado para DB2, MySQL, SQLServer, Sybase, HSQLDB, Informix.
sequence Secuencia DB2, PostgreSQL, Oracle, SAPDB, McKoi, Firebird
i t Obti l id tifi d lt d l t bl l increment Obtiene el identificador ms alto de la tabla y lo incrementa en uno.
hilo Algoritmo hilo. Tipo numrico. Vlido nicamente para una BBDD
uuid.hex 128-bit UUID. Usa la IP y el timestamp para generar la clave. Clave hexadecimal de tamao 32.
19
clave. Clave hexadecimal de tamao 32.
Visin general de Hibernate: acceso a datos
Para recuperar un objeto de la base de datos:
Session terceraSession = UtilidadHibernate.getSessionFactory().openSession();Transaction terceraTransaction =Transaction terceraTransaction = terceraSession.beginTransaction();int ID = 1;
j j ( j )Mensaje mensaje = (Mensaje) terceraSession.get(Mensaje.class, ID);
mensaje.setSiguienteMensaje(new Mensaje("Hola, despus de hola a todo(a)s"));
terceraTransaction.commit();terceraSession.close();
20
Visin general de Hibernate: acceso a datos
Recuperacin de objetos mediante HQL:Session secondSession =
UtilidadHibernate.getSessionFactory().openSession();Transaction secondTransaction = secondSession beginTransaction();Transaction secondTransaction = secondSession.beginTransaction();List messages = secondSession.createQuery("from Mensaje m order by
m.text asc").list();System.out.println("Nmero de elementos: " + messages.size());for ( Iterator iter = messages.iterator(); iter.hasNext(); ) {
Mensaje loadedMsg = (Mensaje) iter.next();System.out.println( loadedMsg.getText() );
}}
secondTransaction.commit();secondSession.close();();
21
Comprobacin de configuracin en Eclipse
Para poder utilizar hibernate tiene que localizar el directorio hibernate-3.2 donde se encuentra hibernate-3.2.jar y las distintas libreras en el j ysubdirectorio \lib. En cualquier proyecto debe situar en el path (Java Build Path) los siguientes jar externos: (para abreviar puede incluir todas)
asm.jar asm-attrs.jar c3p0-0.9.1.jar common-collections.jar common-loggings jar common-loggings.jar dom4j.jar jta.jar Hibernate-3.2.jarj xml-apis.jar eoncurrent-1.3.2.jar ehcache-1.1.jar
f jacc-1_0-fr.jar Jaxen*.jar Jdbc2*.jar Log4* jar
22
Log4 .jar antlr*.jar Cglib*.jar
Comprobacin de configuracin en Eclipse
Por otra parte hibernate tools es un plugin que se encuentra p g qinstalado dentro de eclipse. Compruebe que en File -> New -> Other se puede ver la siguiente
t d Hib tentrada para Hibernate: Compruebe dentro de eclipse que
puede ver la perspectiva Hibernate ConsoleHibernate Console
23
Comprobacin de configuracin en Eclipse
Por ltimo ya que utilizaremos la base de datos HSQLDB debe incluir el jar en el path del proyecto.
24
Creacin de un proyecto ejemplo
Utilizaremos un ejemplo sencillo para mostrar cmo se pueden insertar y obtener objetos de una base de datos HSQLDB utilizando Hibernate.
Queremos almacenar y recuperar Q y pinstancias de la clase Mensaje:
public class Mensaje {private String text;private Mensaje SiguienteMensaje;private Mensaje SiguienteMensaje;
}
25
Creacin de un proyecto ejemplo
Creamos un proyecto java en Eclipse de nombre EjemploHibernate (EjemploHibernate zip en la web)EjemploHibernate (EjemploHibernate.zip en la web)
Es recomendable que no importe el proyecto, los ficheros crelos paso a paso. Para no teclear todo el cdigo puede abrir los ficheros *.java con WordPad y pegar el contenido dentro de archivos de Eclipse.
Dentro del directorio src cree un paquete de nombre Dentro del directorio src cree un paquete de nombre Prueba y dentro de ste el archivo java Mensaje.java.
Toda clase que quiera hacerse persistente debe i l i i t t d tXXX tXXX proporcionar los siguientes mtodos: getXXX y setXXX para
acceder a los atributos.
26
Creacin de un proyecto ejemplo
package Prueba;
public class Mensaje { Script de creacin de
la Base de Datosprivate int id;private String text;private Mensaje SiguienteMensaje;
Mensaje() {}
la Base de Datos
CREATE TABLE MENSAJES (ID_MENSAJE INTEGER GENERATED BY DEFAULT AS IDENTITY(
public Mensaje(String text) {this.text = text;
}
public int getId() {return id;
IDENTITY(START WITH 1, INCREMENT BY 1)
PRIMARY KEY, TEXTO_MENSAJE VARCHAR(255), SIGUIENTE_MENSAJE INTEGER, CONSTRAINT FK_MENSAJES_1 FOREIGN KEY (SIGUIENTE_MENSAJE);
}private void setId(int id) {
this.id = id;}
public String getText() {
( _ )REFERENCES MENSAJES (ID_MENSAJE) ON DELETE
CASCADE);
La clave primaria de la tabla es auto-incrementable.
A d j l ili return text;}public void setText(String text) {
this.text = text;}
public Mensaje getSiguienteMensaje() {
Antes de ejecutar el programa utilice sql explorer para crear la base de datos
public Mensaje getSiguienteMensaje() {return SiguienteMensaje;
}public void setSiguienteMensaje(Mensaje SiguienteMensaje) {
this.SiguienteMensaje = SiguienteMensaje;}
}
27
}
Creacin de un proyecto ejemplo
Cree dentro de src un paquete de nombre persistencia y de nombre persistencia y dentro de ste una clase java de nombre UtilidadHibernate.java.UtilidadHibernate.java.
Copie el contenido de la clase a partir del contenido de a partir del contenido de EjemploHibernate.zip.
d l b Dentro del Paquete Prueba cree la clase Ejemplo1 (marque la opcin que crea el
i ) tit l t id main), sustituya el contenido por el archivo que se encuentra en el zip.
28
Creacin de un proyecto ejemplo
Desde MSDOS edite el archivo runServer bat archivo runServer.bat y sustituya videoteca por mensajes.p j
Abra la perspectiva SQL explorer conecte con la base de datos y con la base de datos y ejecute el script de creacin.
Si aparece un error de conexin compruebe si la base de datos est la base de datos est arrancada.
29
Creacin de un proyecto ejemplo
Para poder usar Hibernate debe activar Hibernate Nature en el proyecto: en el proyecto:
Proyecto -> Properties -> Hibernate Settings Active la pestaa Enable Hibernate 3 Support. Si aparece algn nombre en Default Hibernate Console
Configuration brrelo.
30
Creacin de un proyecto ejemplo
Creacin de los archivos de configuracin de hibernate.g
Dentro del proyecto seleccione: New -> Other. Busque la carpeta Hibernate y
seleccione: Hibernate Configuration File.
Pulse el botn Next. No es necesario que cambie en la No es necesario que cambie en la
siguiente pantalla el nombre del archivo de configuracin (hibernate.cfg.xml).
Pulse Next para pasar a la Pulse Next para pasar a la ventana de configuracin de la base de datos.
31
Creacin de un proyecto ejemplo
Rellene los campos tal como se muestra en la figura.g
Hemos seleccionado la base de datos HSQLDB, el driver y la direccin de la conexin.
No marque la casilla crear consola de configuracin
Pulse Finish. En el browser del proyecto le
aparecer el archivo de configuracin creado. Puede abrirlo con un editor de texto o abrirlo con un editor de texto o bien con un editor XML.
32
Creacin de un proyecto ejemplo
El archivo de configuracin es similar a:
org.hsqldb.jdbcDriverjdbc:hsqldb:hsql://localhost/mensajes
sa
Creacin de un proyecto ejemplo
Ahora crearemos el archivo XML de mapping entre las XML de mapping entre las clase Mensaje y la tabla Mensajes.
Sobre el paquete Prueba Sobre el paquete Prueba pulse: New -> Other -> Hibernate XML mapping File.
Ponga el nombre Ponga el nombre Mensaje.hbm.xml.
En la clase a mapear ponga Prueba MensajePrueba.Mensaje.
34
Creacin de un proyecto ejemplo
El archivo debe contener lo siguiente:
Sustituya el contenido de por: Sustituya el contenido de . por:
35
Creacin de un proyecto ejemplo
Tambin puede utilizar en lugar del anterior, el siguiente archivo de mapping (Mensaje.hbm.xml)
http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd >
name= id column= ID_MENSAJE type = integer >
36
Creacin de un proyecto ejemplo
Creacin de la consola de hibernate, dentro del proyecto , p yseleccione: File -> New -> Other -> Console Configuration.
Rellene los campos tal como se muestra en la figura.
Si aparece el error Ya existe una consola con ese nombre pulse cancelarcancelar
37
Creacin de un proyecto ejemplo
La consola la puede abrir abriendo a su vez la perspectiva Hibernate Console.
La consola puede utilizarse para acceder a la base de datos mediante el lenguaje de consultas de hibernate (explicado en el siguiente captulo).
38
Creacin de un proyecto ejemplo
Por ltimo al ejecutar la aplicacin (lea el archivo Ejemplo1.java) podemos ver la siguiente consola de ejecucin:podemos ver la siguiente consola de ejecucin:
Ignore los mensajes de advertencia (en rojo en la figura). Compare el cdigo del main() con el contenido de la base de
datos.
39
Parte 2: Visin detallada de Hibernate
Obtencin de objetos persistentes. Lenguaje HQL (Hibernate Query Language). Query. Archivos de Mapping. Hibernate Console. Tools Hibernate. Ejemplo guiado.
40
El ciclo de vida de persistencia
La lgica de la aplicacin opera con objetos independientemente de su naturaleza: persistentes (obtenidos de una base de datos) o temporalesp ( ) p(transitorios, existentes nicamente en memoria).
La aplicacin para hacer persistente su estado tiene que interactuar con la p p p qcapa de persistencia, ya sea para propagar su estado desde memoria a la base de datos, o bien a la inversa para obtener el estado desde la base de datos.
En Hibernate para realizar las operaciones anteriores se utiliza el gestor de persistencia y las interfaces de consulta.
41
Objetos transitorios
Los objetos instanciados mediante new no son por defecto persistentespersistentes.
Su estado es transitorio, es decir no estn asociados con ninguna tupla de la base de datos.S estado desapa ece ( a el mecanismo ja a de ecoge bas a) Su estado desaparece (va el mecanismo java de recoge basura) cuando dejan de estar referenciados.
Los objetos referenciados por objetos transitorios son tambin id d t it iconsiderados transitorios.
Para convertirlos en persistentes se utiliza el mtodo save() del gestor de persistencia de Hibernate.
No existe ningn mecanismo de rollback para objetos transitorios, ya que no son transaccionales.
42
Objetos persistentes
Los objetos persistentes son instancias que poseen una identidad en la base de datos (i.e. tienen un atributo que es una clave primaria de una tabla de la BD).
Pueden ser el resultado de una consulta sobre la base de datos, pueden haber sido creados como transitorios y estar asociados al gestor de persistencia mediante el mtodo save(), o bien pueden haber sido persistencia mediante el mtodo save(), o bien pueden haber sido creados desde un objeto persistente.
Las instancias persistentes estn asociadas con una sesin (explicado despus) y son transaccionales (i.e admiten rollback y commit)L i t i i t t ti i t i t d Las instancias persistentes participan en transacciones y su estado se sincroniza con la base de datos cuando sta termina.
Hibernate posee una estrategia (automatic dirty checking) para detectar qu objetos persistentes han sido modificados durante la ejecucin de una q j p jtransaccin, y gestiona de manera transparente la modificacin en la base de datos (actualizacin, borrado, insercin).
Por defecto en una actualizacin modifica todos los campos de la tabla, puede cambiarse el comportamiento (modificar nicamente los campos puede cambiarse el comportamiento (modificar nicamente los campos necesarios) si en el archivo de mapping de la clase se utiliza:
Dynamic-update =true
43
Objetos separados/independientes
Los objetos persistentes se convierten en separados cuando termina una transaccin y se cierra una sesin del gestor de termina una transaccin y se cierra una sesin del gestor de persistencia.
Desde ese momento no se garantiza que su estado est sincronizado con el estado de los objetos que existen en la base de datosbase de datos.
Si siguen referenciados por la aplicacin, pueden ser reutilizados en una nueva sesin con lo cual se convierten de nuevo en persistentes.
La operacin evit() es una operacin de separacin explcita de objetos, se utiliza normalmente por
id i d fi i i d l h ( li d
44
consideraciones de eficiencia de la cach (explicado despus).
El gestor de persistencia
Cualquier gestor de persistencia transparente proporciona una API con servicios para:
Operaciones bsicas CRUD (Create, Read, Update, Delete). Ejecucin de consultas. Control de transacciones. Gestin de la cach a nivel de transacciones Gestin de la cach a nivel de transacciones.
En Hibernate se emplean diferentes interfaces: Session, Query, Criteriay Transaction para poder utilizar el gestor de persistencia.
La interfaz ms importante, aunque todas estn relacionadas, es Session, normalmente se asocia con el gestor de persistencia (i.e session y gestin de persistencia se consideran trminos intercambiables).
45
Convertir en persistente un objeto
Dentro de una sesin para convertir un objeto transitorio en persistente se utiliza el mtodo save().()User user = new User();user.getName().setFirstname("John");user.getName().setLastname("Doe"); g () ( );Transaction tx = session.beginTransaction();session.save(user);tx.commit(); // session.flush();tx.commit(); // session.flush();session.close();
La sincronizacin con la base de datos se realiza al ejecutar el mtodo commit() de la transaccin. ()
En ese punto Hibernate obtiene una conexin JDBC ejecuta un sentencia SQL de insercin y al cerrar la sesin la conexin tambin se cierra.
Si la transaccin falla el rollback se realiza a nivel de base de datos no a nivel de objetos en memoria.
46
Actualizar el estado persistente de una instancia separada 1/2
Cuando se cierra una sesin la instancia de usuario del ejemplo anterior se convierte en separada, perdindose la sincronizacin de estado con la base p , pde datos. Puede de nuevo convertirse en persistente con update() y lock().
El mtodo update() fuerza una actualizacin del estado persistente en la base de datos, generando una sentencia sql update.
user.setPassword("secret");Transaction tx = sessionTwo.beginTransaction();sessionTwo update(user);sessionTwo.update(user);user.setUsername("jonny");tx.commit();sessionTwo.close();();
La llamada a update() hace que el objeto se trate como dirty.
Observe que en el ejemplo el estado (nombre de usuario) se cambia Observe que en el ejemplo el estado (nombre de usuario) se cambia despus de invocar update(), esto es irrelevante para Hibernate. El nuevo estado se salvar en la base de datos al ejecutar commit().
47
Actualizar el estado persistente de una instancia separada 2/2
La invocacin del mtodo lock() asocia el objeto con la sesin actual sin forzar la actualizacin.
Transaction tx = sessionTwo.beginTransaction();sessionTwo.lock(user, LockMode.NONE);( , );user.setPassword("secret");user.setLoginName("jonny");tx.commit();tx.commit();sessionTwo.close();
Los cambios realizados a la instancia antes de llamar a lock() no se Los cambios realizados a la instancia antes de llamar a lock() no se propagan a la base de datos.
48
Obtener un objeto persistente
La sesin se utiliza tambin para obtener objetos persistentes, aunque Hibernate posee un lenguaje de consultas (explicado despus), se puede p g j ( p p ), pemplear el mtodo get() de sesin para obtener un objeto mediante su clave.
Transaction tx = session.beginTransaction();int userID = 1234;User user = (User) session.get(User.class, new Long(userID));tx commit();tx.commit();session.close();
El mtodo get() busca el objeto cuyo id sea 1234. Si no existe ninguno El mtodo get() busca el objeto cuyo id sea 1234. Si no existe ninguno con esa clave devuelve null.
Una vez cerrada la sesin el objeto pasa al estado separado.Una vez cerrada la sesin el objeto pasa al estado separado.
49
Actualizar un objeto persistente
Cualquier objeto persistente se encuentra asociado con una sesin (contexto de persistencia)(contexto de persistencia).
Si se modifica su estado mediante el mecanismo llamado automatic dirty checking Hibernate lleva a cabo la sincronizacin con la base de datos dentro del contexto actual de persistenciacon la base de datos dentro del contexto actual de persistencia.
Transaction tx = session.beginTransaction();i t ID 1234int userID = 1234;User user = (User) session.get(User.class, new Long(userID));user.setPassword("secret");tx.commit();session.close();
Cuando se ejecuta commit() se produce la sincronizacin. Obviamente al cerrar la sesin el objeto pasa al estado separado.
50
Convertir un objeto persistente en removed.
Los objetos persistentes se pueden convertir en transitorios mediante el mtodo delete().()
Transaction tx = session.beginTransaction();int userID = 1234;User user = (User) session.get(User.class, new Long(userID));session.delete(user);tx.commit();session close();session.close();
La sentencia SQL de borrado se ejecuta cuando la sesin se sincroniza con la base de datos mediante el commit.
Al cerrar la sesin el objeto se convierte en transitorio, si desaparecen las referencias al mismo, el mecanismo de liberacin de memoria lo destruye., y
51
Obtencin de objetos persistentes
Para extraer objetos desde la base de datos en Hibernate se pueden utilizar las siguientes opciones:g p
Navegar por el grafo de objetos: Una vez cargado un objeto y dentro de una sesin se puede acceder a sus propiedades y mtodos. Esto origina que el
t d i t i t ti t l d ( bj t ) l i t t gestor de persistencia cargue automticamente los nodos (objetos) al intentar acceder por navegacin a alguna de sus propiedades.
unPedido.Cliente.getNombre();
Obtenerlos mediante el identificador (id), es el mtodo ms conveniente cuando el identificador se conoce.
Utilizando el lenguaje de consultas de Hibernate (HQL) una versin orientada a Utilizando el lenguaje de consultas de Hibernate (HQL) una versin orientada a objetos de SQL.
Utilizando el lenguaje SQL nativo de la base de datos, donde Hibernate realiza l i d l i t (JDBC lt t) f d bj t la conversin de los registros (JDBC result set) en grafos de objetos persistentes.
52
Lenguaje de consultas de Hibernate (HQL)
HQL es un dialecto orientado a objetos del lenguaje SQL. HQL no es un lenguaje de manipulacin de datos al estilo de SQL HQL no es un lenguaje de manipulacin de datos al estilo de SQL,
se utiliza nicamente para obtener datos. Usualmente no se utiliza para actualizaciones, inserciones y borrados.El gesto de pe sistencia se enca ga de la sinc oni acin (de El gestor de persistencia se encarga de la sincronizacin (de acuerdo al estado) de los objetos con la base de datos.
Las caractersticas principales son las siguientes: Permite obtener nicamente propiedades de una entidad o entidades
sin necesidad de cargar el contenido de toda ella (proyeccin). Permite la ordenacin y paginacin del resultado de consultas.
Ad i l d d b h i f i d Admite consultas de agregado con group by, having y funciones de agregado como sum,min,max.
Joins externos.P ibilid d d i f i SQL d fi id l i Posibilidad de invocar funciones SQL definidas por el usuario.
Consultas anidadas.
53
Lenguaje de consultas de Hibernate (HQL)
HSQL se encarga de la traduccin de consultas realizadas sobre objetos a consultas realizadas sobre registros y a la inversa, convierte los registros g y , gen objetos.
Sobre el diagrama de clases de diseo, la consulta HSQL:
FROM Persona P where P.categoria.id = 3 Se traduce en la sentencia SQL:
S l t ID N b A llid f P h t i 3Select ID, Nombre, Apellidos from Personas where categoria =3
54
Consultas HQL
Consultas simples: Clusula from: selecciona instancias.From Usuarios // devuelve todas las instancias de usuariosFrom Usuarios // devuelve todas las instancias de usuarios.From Usuarios as usuario // similar al anterior utilizando una aliasFrom Usuarios, Grupo // Producto Cartesiano Clusula select: selecciona objetos y propiedades que devuelve en la consultaselect cliente.contacto.Apellido from Cliente as cliente
Clusula where:from Usuarios as usuario where usuario.nombre='mariaselect usuario.nombre from Usuarios usuario where usuario.nombre like 'mari%from Documentos doc, Usuarios usuario where doc.usuario.nombre = usuario.nombre
La propiedad especial id puede utilizarse para referirse al nico identificador de un objeto.
f D t d h d id 131512from Documentos as doc where doc.id = 131512from Documentos as doc where doc.autor.id = 69
Clusula order by:from Usuarios usuario order by usuario.nombre asc, usuario.fechaCreacion desc, user.emaily , ,
Group by:select sum(documento) from Documentos documento group by documento.categoria
55
Query: definicin de consultas
La interface Query define varios mtodos para controlar la ejecucin de consultas.
Para crear una consulta, en el contexto de una sesin, se utilizan los mtodos createQuery() y createSQLQuery:
createQuery() se emplea para consultas HQL:Query hqlQuery = session.createQuery("from Usuario");
createSQLQuery se usa para consultas en SQL nativo:Query sqlQuery = session.createSQLQuery("select {u *} from USUARIOS {u}" "u" Usuario class);"select {u.*} from USUARIOS {u}", "u", Usuario.class);O de manera alternativa:Query sqlQuery = session.createSQLQuery("select {usuario.*} from USUARIOS
{usuario}").addEntity("usuario", Usuario.class);
En ambos casos se obtiene una instancia del objeto Query pero no se ejecuta ninguna consulta sobre la base de datos.
56
Query: paginacin y enlace de parmetros
La interfaz Query soporta la paginacin de resultados:Query query = session.createQuery("from Usuario u order by u.nombre asc");query.setMaxResults(10);
Incluso en consultas sql nativas, Hibernate se encarga de reescribir la consulta:Query sqlQuery = session.createSQLQuery("select {u.*} from USUARIOS {u}") .addEntity("u", Usuario.class);sqlQuery.setFirstResult(40);sqlQuery.setMaxResults(20);
Los parmetros de una consulta parametrizada se pueden enlazar por posicin o por nombre:
Query q = session.createQuery("from Event where name = ? ");q setParameter(0 "Opening Plenary");q.setParameter(0, Opening Plenary );q.setParameter(0, "Opening Plenary", Hibernate.STRING); //equivalente al anterior
En los parmetros por nombre no es necesario utilizar la posicin:Query q = session.createQuery("from Event where name = :name");q.setParameter("name", "Opening Plenary");
57
Query: paginacin y enlace de parmetros 2/2
El enlace de parmetros admite tambin formas abreviadas:
String queryString = "from Item item + " where item.description like :search + " and item.date > :minDate";
Query q = session.createQuery(queryString).setString("search", i isearchString).setDate("minDate", mDate);
Por defecto Hibernate, antes de ejecutar una operacin de consulta, efecta una actualizacin (flush) del contexto de persistencia para efecta una actualizacin (flush) del contexto de persistencia para garantizar que los datos obtenidos por la consulta son datos actuales y no entran en conflicto con los datos en memoria.
En algunas situaciones como una secuencia de consulta-modificacin-gconsulta-modificacin, donde se sabe que no hay conflicto entre los datos en memoria y en la base de datos se puede cambiar el comportamiento por defecto utilizando el mtodo setFlushMode().
Query q = session.createQuery(queryString).setFlushMode(FlushMode.COMMIT);
58
Query: ejecucin e iteracin sobre el resultado
El mtodo list() ejecuta las consultas asociadas a una Query y devuelve el resultado como una lista de java.util.List;List result = myQuery.list();
El mtodo iterate() permite tambin ejecutar consultas.Query categoryByName =session.createQuery("from Category c where c.name like :name");categoryByName.setString("name", categoryNamePattern);Iterator categories = categoryByName.iterate();
Con iterate() la ejecucin obtiene la id de las instancias de categora, cuando se itera sobre el resultado el resto de la informacin la busca en la cach, si no existe genera otra consulta de seleccin. til cuando est tambin habilitada la cach de segundo nivel en otro caso genera n+1 consultas de seleccin.
Si se quiere obtener toda la informacin debe utilizarse:Query categoryByName =Query categoryByName =session.createQuery("from Category c where c.name like :name");categoryByName.setString("name", categoryNamePattern);List categories = categoryByName.list();
59
g g y y
Ejemplo Mapping:Transformaciones de una clase
Clase sin relaciones public void setApellido(String apellido) {Apellido = apellido;
public class Contacto implementsSerializable {private int id;private String Nombre;
Apellido = apellido;}public String getEmail() {return email;}p gprivate String Apellido;
private String email;
public Contacto() {
}public void setEmail(String email) {this.email = email;}public int getId() {pub c Co tacto() {
//constructor por defecto}public Contacto(String nombre, String
apellido, String email, int id) {
public int getId() {return id;}public void setId(int id) {this id = id;p , g , ) {
Nombre = nombre;Apellido = apellido;this.email = email;this.id = id;
this.id = id;}public String getNombre() {return Nombre;}this.id id;
}public String getApellido() {return Apellido;}
}public void setNombre(String nombre)
{Nombre = nombre;}
60
} }}
Ejemplo Mapping:Transformaciones de una clase
Archivo de correspondenciapp g
61
Mapping Especializacin
Hay tres formas de traducir una jerarqua de especializacin a tablas relacionales:tablas relacionales:
Una tabla por cada subclase. Una tabla para toda la jerarqua. Una tabla por cada clase de la jerarqua Una tabla por cada clase de la jerarqua.
-propietario : stringDetallesFacturacion
Visual Paradigm for UML Community Edition(Universidad Polit?nica de Valencia)
-Numero : string-fechaExpedicion : string
TarjetaCredito-NumCuenta : string-banco : string
CuentaBancaria
Aunque hay 4 tipos de archivos de correspondencia, que en Hibernate se llaman:
-fechaCaducidad : string -CodigoSWIFT : string
Hibernate se llaman: Tabla por cada clase concreta sin polimorfismo implcito. Tabla por cada clase concreta (con uniones).
Una tabla para toda la jerarqua
62
Una tabla para toda la jerarqua. Una tabla por cada clase de la jerarqua.
Especializacin: Tabla por cada clase concreta sin polimorfismo implcito.
Se utiliza una tabla por cada clase no abstracta, en el ejemplo el modelo relacional queda:modelo relacional queda:
Tarjeta de crdito TarjetaCreditoID (clave primaria) Propietario Numero FechaExpedicion
Cuenta Bancaria CuentaID (clave primaria) Propietario NumCuenta Banco
Los archivos de correspondencia de cada subclase son
FechaExpedicion FechaCaducidad
BancoCodigoSwift
pindependientes y se crean como en el ejemplo precedente.
La jerarqua de clases existe en la capa de dominio, pero en elmodelo relacional existen tablas para las subclases nicamente.modelo relacional existen tablas para las subclases nicamente.
63
Especializacin: Tabla por cada clase concreta sin polimorfismo implcito.
Inconvenientes: No apropiado si se necesitan consultas polimrficas sobre la No apropiado si se necesitan consultas polimrficas sobre la
superclase. Una consulta SQL sobre detalles de facturacin tieneque traducirse en tantas consultas como subclases de la jerarqua.
Tampoco puede utilizarse si las superclase tiene relaciones a poco puede ut a se s as supe c ase t e e e ac o espolimrficas como la de la figura:
DetallesFacturacionVisual Paradigm for UML Community Edition(Universidad Polit?nica de Valencia) 0*1
-propietario : string
C C
Clase A
-Numero : string-fechaExpedicion : string-fechaCaducidad : string
TarjetaCredito-NumCuenta : string-banco : string-CodigoSWIFT : string
CuentaBancaria
64
Especializacin: Tabla por cada clase concreta con uniones.
Es una variacin de la estrategia anterior. Para el ejemplo existen como en el caso anterior dos tablas.a a j p o o o a o a o do ab a Se utiliza un archivo de correspondencia.
/...
i i /
...
65
Especializacin: Tabla por cada clase concreta con uniones.
En una consulta sobre DetallesFacturacion Hibernate genera una consulta de unin con las tablas del ejemploconsulta de unin con las tablas del ejemplo.
Las relaciones polimrficas son tambin posibles, ya que Hibernate se encarga de simular la tabla asociada a la superclase.
66
Especializacin: Tabla para toda la jerarqua
La jerarqua completa se traduce a una nica tabla. Se desnormaliza el modelo relacional y es necesario introducir un Se desnormaliza el modelo relacional y es necesario introducir un
discriminador. Funciona bien con las consultas polimrficas. Tiene el inconveniente de los valores no nulos en las tablas
asociadas a las subclases, ahora pueden tomar valores nulos. Detalles Facturacin DetallesID (clave primaria)DetallesID (clave primaria)TipoDetalles (discriminador) Propietario NumCuenta Banco CodigoSwift NNumero FechaExpedicion FechaCaducidad
67
Especializacin: Tabla para toda la jerarqua
En el archivo de correspondencia se define la traduccin de la siguiente forma:
< t l " ti "/>
...
...
68
Especializacin: Tabla para cada clase.
Cada clase de la jerarqua se traduce en una tabla. La claveprimaria de la tabla asociada a la superclase acta como claveprimaria de la tabla asociada a la superclase acta como claveprimaria y ajena en las tablas asociadas a las subclases.
Detalles Facturacin DetallesID (clave primaria)( p )Propietario
Tarjeta de crdito TarjetaCreditoID (clave primaria) Numero FechaExpedicion
Cuenta Bancaria CuentaID (clave primaria) FechaExpedicion
FechaCaducidad
CuentaID (clave primaria) NumCuenta Banco CodigoSwift
El esquema est normalizado, las asociaciones polimrficas sonfcilmente representables mediante claves ajenas.Si l j l j d ti l fi i i l Si la jerarqua es compleja puede resentirse la eficiencia en lasconsultas.
69
Especializacin: Tabla para cada clase.
Con respecto al archivo de correspondencia, tiene la forma:
Relaciones y colecciones
La multiplicidad en el modelo conceptual de las relaciones de asociacin /agregacin puede ser:asociacin /agregacin puede ser:
1:1 (one-to-one) N:1 (many-to-one) 1:N (one to many) 1:N (one-to-many) N:M (many-to-many)
En el caso de relaciones con multiplicidades muchos, surge el concepto de coleccin en Hibernateconcepto de coleccin en Hibernate.
Hibernate contiene las siguientes colecciones:
Coleccin Hibernate Coleccin Java Descripcin set java.util.Set Coleccin no ordenada de valores de objetos sin repeticiones. map java.util.Map Coleccin de pares clave/valor. list java.util.List Coleccin ordenada de valores de objetos, admite repetidos. b j til Li t C l i d d d l d bj t d it tidbag java.util.List Coleccin no ordenada de valores de objetos, admite repetidos.array - Coleccin indexada, con repetidos, de valores de objetos. primitive-array - Coleccin indexada, con repetidos, de valores primitivos. idbag java.util.List Coleccin muchos a muchos no ordenada, con repetidos, utilizando
una clave adicional.
71
Ejemplo: Preparacin Primero:
Cree el proyecto videotecaA d l lib hib t 23 j l t d Aada la librera hibernate23.jar y las encontradas en /lib
Active Project|Preferences|Hibernate SettingsC l t N i Cree el paquete Negocio
Utilizaremos el diagrama de clase de la figura
72
Ejemplo: Preparacin
Para cada clase: Atributos privados
package Negocio;import java.util.Collection;import java.util.HashSet;import java.util.Iterator;import java.util.Set; Atributos privados.
Colecciones persistentes deben implementar una
import java.util.Set;public class Director {private int iddirector;private String nombre = "";private Set peliculas = new HashSet();
interfaz: Set peliculas = new
HashSet(); List peliculas = new
public Director(){ }
public int getIddirector() {return iddirector;}private void setIddirector(int iddirector) {this.iddirector = iddirector;}
List peliculas = new ArrayList();
Constructor por defecto sin cdigo ni parmetros
public String getNombre() {return nombre;}public void setNombre(String nombre) {this.nombre = nombre;}public Set getPeliculas() {return peliculas;}
sin cdigo ni parmetros. Getters y setters
pblicos para cada
public Iterator peliculasIterator() {return peliculas.iterator();}public boolean addPeliculas(Pelicula pelicula) {
return peliculas.add(pelicula);}public void setPeliculas(HashSet peliculas) {this.peliculas = peliculas;}
atributo. Atributo identificador (id)
con setter privado.
public boolean isPeliculasEmpty() {return peliculas.isEmpty();}public boolean removePeliculas(Pelicula pelicula) {return peliculas.remove(pelicula);}
73
con setter privado. }
Ejemplo: Preparacin
Cree el paquete AccesoADatos Disee el modelo relacional con Clay (ModeloRelacional.clay).
D l l l i i t i tDeclare las claves primarias como auto-increment Genere el script de definicin de la BD (ModeloRelacional.sql) Arranque HSQLDB en modo servidor, creando una bd vaca
(videoteca)(videoteca). Ejecute el script ModeloRelacional.sql desde SQL Explorer Importe y ejecute el script LlenarTablas.sql
74
Ejemplo: Ficheros de mapping
Inicialmente vamos a definir relaciones unidireccionales File | New | Other | Hibernate XML Mapping File File | New | Other | Hibernate XML Mapping File Mapping Pelicula:
Estrategia de generacin de ids: escoge la mejor
l SGBD
Ejemplo: Ficheros de mapping
Mapping Director.< l "Di t " t bl "DIRECTOR" h "PUBLIC l "f l ">
lazy permite que se carguen en memoria los
objetos que forman parte de una asociacin
/
Mapping Genero.
Ejemplo: Fichero de configuracin de Hibernate
Desde la carpeta src del proyecto: New |Other | Hibernate -> Hibernate Configuration File
Hibernate Configuration File
//Hibernate/Hibernate Configuration DTD 3.0//EN"http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
org.hsqldb.jdbcDriver
jdb h ldb h l //l lh t/ idname="hibernate.connection.url">jdbc:hsqldb:hsql://localhost/video
tecasaorg.hibernate.dialect.HSQLDialect
Aadir a
77
mano
Ejemplo.
Cree el paquete utilidades y dentro de ste incluya la clase UtilidadHibernate.java.j
Incluya la clase capanegocio.java en el paquete Negocio. Cree el paquete DemoMulticapaHibernate y cree la clase
Principal java con mtodo main()Principal.java con mtodo main(). Cree el paquete AccesoADatos y ponga dentro las interfaces
DAO y las clases DAO para usar con Hibernate, segn se explica a continuacin.
78
Ejemplo Paquete AccesoAdatos
Crear la clase PeliculaDAOHibernateImp que implementa a la interfaz IPeliculaDAO:la interfaz IPeliculaDAO:
public class PeliculaDAOHibernateImp implements IPeliculaDAO {
private Session sesion = null; // Hibernate Sessionprivate Transaction tx = null; // Hibernate Transaction
public void createMovie(Pelicula p) {// TODO Auto-generated method stubtry {
sesion = UtilidadHibernate.getSessionFactory().openSession();tx = sesion.beginTransaction();sesion.save(p);tx.commit();
} catch (HibernateException e) { rollback(); throw e;} finally {ysesion.close();}
}
79
Paquete AccesoAdatos: Dao Pelcula
Las operaciones DAO utilizan a Session, Query y Transaction:Transaction:
private void rollback(){try {
if (tx != null) {tx.rollback();
}} catch (HibernateException ignored) {
// No se puede hacer rollback de la transaccin;}
}
El resto de operaciones tienen el mismo patrn: Abrir sesin, iniciar transaccin Llamar a la correspondiente operacin de sesion (update delete Llamar a la correspondiente operacin de sesion (update, delete,
etc.), o bien utilizar el lenguaje de consultas de Hibernate. Commit sobre la transaccin. Cerrar la sesin.
80
Cerrar la sesin.
Paquete AccesoAdatos: Dao Pelcula
Para borrar una pelcula por id.
public void deleteMovie(int id) throws PeliculaNoEncontradaExcepcion{// TODO Auto-generated method stubtry {try {sesion = UtilidadHibernate.getSessionFactory().openSession();tx = sesion.beginTransaction();Object pelicula = sesion.load(Pelicula.class, id);
i d l t ( li l )sesion.delete(pelicula);tx.commit();
} catch (HibernateException e) {rollback();throw new PeliculaNoEncontradaExcepcion();
} finally {
sesion.close();}
}
81
Paquete AccesoAdatos: Dao Pelcula
O bien pasando el objeto a borrar.
public void deleteMovie(Pelicula p) throws PeliculaNoEncontradaExcepcion{// TODO Auto-generated method stubgtry {
sesion = UtilidadHibernate.getSessionFactory().openSession();tx = sesion.beginTransaction();sesion.delete(p);(p);tx.commit();
} catch (HibernateException e) {rollback(); throw new PeliculaNoEncontradaExcepcion();
}} finally {
sesion.close();}
}}
82
Paquete AccesoAdatos: Dao Pelcula
Para obtener todas las pelculas:
public ArrayList findPeliculas() {// TODO Auto-generated method stubtry {y
sesion = UtilidadHibernate.getSessionFactory().openSession();sesion.beginTransaction();
ArrayList ListaPeliculas = (ArrayList) sesion.createQuery("from Pelicula").list();
sesion.getTransaction().commit();return ListaPeliculas;
}catch (HibernateException e) {( p ) {
rollback(); throw e;}
finally {sesion.close();ses o .c ose();}
83
Ejemplo: Capa Negocio
La capa de negocio contiene: Un paquete con la definicin de las clases Pelicula, Director y p q , y
Genero. Una clase de nombre capadenegocio con las colecciones
ListaPelicula, ListaDirectores y ListaGenerosListaPelicula, ListaDirectores y ListaGeneros
public class capanegocio {private ArrayList ListPeliculas = null;private ArrayList ListGeneros = null;private ArrayList ListDirectores = null;private ArrayList ListDirectores = null;
static private capanegocio ref_capanegocio = new capanegocio();private capanegocio() {}
static public capanegocio getCapaNegocio(){return ref capanegocio;_ p g}
public void finalize(){ UtilidadHibernate shutdown();
84
UtilidadHibernate.shutdown();}
}
Capa de negocio: clase capanegocio
El resto de los mtodos es de la forma:public void GetPeliculas()
{ if (ListPeliculas == null){{PeliculaDAOHibernateImp PeliculaDAOH = new PeliculaDAOHibernateImp();ListPeliculas = PeliculaDAOH.findPeliculas();}}}
public ArrayList GetListaPeliculas(){
t Li tP li lreturn ListPeliculas;}
85
Ejemplo: Capa Negociopublic void UpdatePelicula(Pelicula p1)
{ // actualiza la capa de negocio con la pelcula p, la busca por oidPelicula p = null;pfor (int i = 0; i < ListPeliculas.size(); i++)
{ p = (Pelicula) ListPeliculas.get(i);if (p.getIdpelicula()== p1.getIdpelicula()) {
ListPeliculas set(i p1);ListPeliculas.set(i, p1);break;
}}
PeliculaDAOHibernateImp PeliculaDAOH = new PeliculaDAOHibernateImp();t {try {PeliculaDAOH.updateMovie(p);
} catch (PeliculaNoEncontradaExcepcion e) {// TODO Auto-generated catch blocke.printStackTrace();
}}
86
Ejemplo: Probar la aplicacin
public static void main(String[] args) {capanegocio micapanegocio = capanegocio.getCapaNegocio();// Cargar objetos desde la BDmicapanegocio.GetPeliculas();micapanegocio.GetDirectores();micapanegocio.GetGeneros();micapanegocio.ListarPeliculas();// Aade una PelculaDirector d = (Director) micapanegocio.GetDirectorActual(1);Genero g = (Genero) micapanegocio.GetGeneroActual(1);Pelicula p = new Pelicula();p.setDirector(d);
tG ( )p.setGenero(g);p.setFecha("2007");p.setTitulo("Pelicula Nueva");micapanegocio AddPelicula(p);
87
micapanegocio.AddPelicula(p);micapanegocio.ListarPeliculas();
Ejemplo: Probar la aplicacin
// Borrar la Pelicula con id=2micapanegocio.BorrarPelicula(2);micapanegocio.ListarPeliculas();
// Actualizar la Pelicula con id=3Pelicula p2 = (Pelicula) micapanegocio.GetPeliculaOID(3);p2.setTitulo("Pelicula actualizada");micapanegocio.UpdatePelicula(p2);micapanegocio.ListarPeliculas();
}
88
Ejemplo
El explorador de paquetes debe mostrar esta estructura
89
Modificaciones a la aplicacin Generacin de claves por programa
En los ficheros de mapping .hbm.xml sustituir native por assignedE l di j En el cdigo .java:
Cambiar la visibilidad de los mtodos setIdXXX a public Implementar el algoritmo de asignacin de ids en la capa de negocio. En la
aplicacin ejemplo se utiliza el mtodo GetNextOIDPelicula()
Implementacin de asociaciones bidireccionales Para representar la relacin one-to-many entre Director y Pelicula, se
aade en el fichero Director.hbm.xml
90
Referencias
Hibernate in action. Christian Bauer; Gavin King. Manning 2005. Hibernate Quickly Patrick Peak; Nick Heudecker Manning 2006 Hibernate Quickly. Patrick Peak; Nick Heudecker. Manning 2006. Java Persitence with Hibernate. Christian Bauer; Gavin King. Manning
2007. Cachs, concurrencia e Hibernate. Martn Prez Marin accesible en:Cachs, concurrencia e Hibernate. Martn Prez Marin accesible en:
http://www.javahispano.org/articles.article.action?id=95
91