Está en la página 1de 25

Tutorial basico de Hibernate

http://www.davidmarco.es/tutoriales/hibernate-reference/

Tutorial basico de Hibernate


por Gavin King, Christian Bauer, Max Rydahl Andersen, Emmanuel Bernard, y Steve Ebersole agradecimientos a James Cobb (Diseo Grafico) y Cheyenne Weaver (Diseo Grafico)

Traduccion a Espaol
por David Marco Palao (programacion@davidmarco.es)

3.3.2.GA
Parte 1 - La primera Aplicacion Hibernate 1.1 Configuracion 1.2 La primera clase 1.3 El archivo de mapeo 1.4 Configuracion de Hibernate 1.5 Construyendo con Maven 1.6 Puesta en marcha y clases de ayuda 1.7 Leyendo y almacenando objetos Parte 2 - Mapeo de asociaciones 2.1 Mapeando la clase Persona 2.2 Una asociacion unidireccional basada en Set 2.3 Trabajando con la asociacion 2.4 Colecciones de valores 2.5 Asociaciones bidireccionales 2.6 Trabajando con enlaces bidireccionales Part 3 - La aplicacion web EventManager 3.1 Escribiendo un servlet basico 3.2 Procesando la solicitud y formando la pagina de respuesta 3.3 Desplegando y probando Resumen Este capitulo, pensado para nuevos usuarios, ofrece una introduccion paso a paso a Hibernate, comenzando con una sencilla aplicacion que usa una base de datos en memoria. El tutorial esta basado en un tutorial anterior desarrollado por Michal Gloegl. Todo el codigo fuente puedes encontrarlo en el directorio
project/tutorials/web de tu distribucion de Hibernate.

Importante
Este tutorial asume que el usuario tiene conocimientos tanto de Java como de SQL. Si dispones de un conocimiento limitado de Java y SQL es aconsejable que comiences con una buena introduccion a estas tecnologias como paso previo a intentar aprender Hibernate.

1 de 25

28/02/2010 22:34

Tutorial basico de Hibernate

http://www.davidmarco.es/tutoriales/hibernate-reference/

Nota
La distribucion de Hibernate contiene otra aplicacion de ejemplo bajo el directorio de proyectos
tutorial/eg.

Parte 1 - La primera Aplicacion Hibernate


Para este ejemplo, vamos a poner en marcha una pequea aplicacion de base de datos que puede almacenar eventos que queremos atender, asi como informacion sobre el origen (host) de dichos eventos.

Nota
Aunque puedes usar cualquier base de datos con la que te sientas comodo, nosotros vamos a usar HSQLDB (una base de datos en memoria escrita en Java) para evitar describir la instralacion y puesta en marcha de un servidor de bases de datos en concreto.

1.1 Configuracion
Lo primero que necesitamos hacer es poner en marcha el entorno de desarrollo. Usaremos el "esquema estandar" defendido por un monton de herramientas de construccion como Maven. Maven, en particular, dispone de un buen recurso web describiendo este esquema. Como este tutorial es una aplicacion web, crearemos y haremos uso de los directorios src/main/java, src/main/resources y src/main/webapp. Usaremos Maven en este tutorial, tomando ventaja de sus capacidades de gestion de dependencias asi como la habilidad de muchos IDE's de configurar automaticamente un proyecto basandose en el descriptor Maven.

2 de 25

28/02/2010 22:34

Tutorial basico de Hibernate

http://www.davidmarco.es/tutoriales/hibernate-reference/

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>org.hibernate.tutorials</groupId> <artifactId>hibernate-tutorial</artifactId> <version>1.0.0-SNAPSHOT</version> <name>First Hibernate Tutorial</name> <build> <!-- we dont want the version to be part of the generated war file name --> <finalName>${artifactId}</finalName> </build> <dependencies> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-core</artifactId> </dependency> <!-- Because this is a web app, we also have a dependency on the servlet api. --> <dependency> <groupId>javax.servlet</groupId> <artifactId>servlet-api</artifactId> </dependency> <!-- Hibernate uses slf4j for logging, for our purposes here use the simple backend --> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-simple</artifactId> </dependency> <!-- Hibernate gives you a choice of bytecode providers between cglib and javassist --> <dependency> <groupId>javassist</groupId> <artifactId>javassist</artifactId> </dependency> </dependencies> </project>

Consejo
Usar Maven no es obligatorio. Si deseas usar cualquier otra herramienta para construir este tutorial (como Ant) el esquema seguira siendo el mismo. El unico cambio es que necesitaras manipular manualmente todas las dependencias requeridas. Si utilizas una herramienta como Ivy ofreciendo mantenimiento transitivo de dependencias, seguiras necesitando las dependencias mencionadas debajo. De cualquier otra manera necesitaras tener todas las dependencias, tanto explicitas como transitivas, y aadirlas al classpath del proyecto. Si estas trabajando con el paquete de distribucion de Hibernate, estas dependencias son hibernate3.jar,

3 de 25

28/02/2010 22:34

Tutorial basico de Hibernate

http://www.davidmarco.es/tutoriales/hibernate-reference/

todos los archivos del directorio lib/required asi como todos los archivos de los directorios
lib/bytecode/cglib o lib/bytecode/javassist; de manera adicional, necesitaras tanto el archivo

jar del servlet API como una de las implementaciones del API para logging slf4j.

Guarda este archivo como pom.xml en el directorio principal del proyecto.

1.2 La primera clase


A continuacion creamos una clase que representa el evento que queremos almacenar en la base de datos; es una sencilla clase JavaBean con algunas propiedades:
package org.hibernate.tutorial.domain; import java.util.Date; public class Event { private Long id; private String title; private Date date; public Event() {} public Long getId() { return id; } private void setId(Long id) { this.id = id; } public Date getDate() { return date; } public void setDate(Date date) { this.date = date; } public String getTitle() { return title; } public void setTitle(String title) { this.title = title; } }

La clase usa nombres estandar JavaBean para los metodos getter y setter de cada propiedad, asi como visibilidad privada para las variables. Aunque este es el diseo recomendado no es obligatorio, ya que Hibernate puede acceder a las variables directamente. Sin embargo, el uso de metodos de acceso es beneficioso por su robustez a la hora de refactorizar.

4 de 25

28/02/2010 22:34

Tutorial basico de Hibernate

http://www.davidmarco.es/tutoriales/hibernate-reference/

La propiedad id almacena un valor que identifica de manera unica cada evento. Todas las clases que representan entidades persistentes (asi como otras clases dependientes menos importantes) necesitaran dicha propiedad identificativa si queremos hacer uso de todo el conjunto de caracteristicas de Hibernate. De hecho, muchas aplicaciones, especialmente aplicaciones web, necesitan distinguir ciertos objetos por su identidad, por lo que debes considerarlo como una caracteristica en lugar de como una limitacion. Sin embargo, normalmente no manipularemos la identidad de un objeto , por lo que su metodo setter debe ser privado. Solo Hibernate asignara la identidad cuando un objeto sea almacenado en la base de datos. Hibernate puede acceder tanto metodos de acceso de tipo publico, privado y protegido, como directamente las variables tambien de tipo publico, privado y protegido. Esta eleccion es tuya y puedes elegir la que mejor se ajuste al diseo de tu aplicacion. El constructor sin argumentos es necesario para todas las clases persistentes; Hibernate tiene que crear objetos por ti, usando reflexion. El constructor puede ser privado, aunque se requiere que tenga visibilidad publica o de paquete para la generacion de proxys en tiempo de ejecucion, y para recuper datos de forma eficiente sin manipular del codigo de bytes. Guarda este archivo en el directorio src/main/java/org/hibernate/tutorial/domain.

1.3 El archivo de mapeo


Hibernate necesita saber como leer y almacenar objetos de una clase persistente. Aqui es donde el archivo de mapeo de Hibernate entra en juego. El archivo de mapeo indica a Hibernate que tabla en la base de datos tiene que ser accedida, y que columnas en dicha tabla deben usarse. La estructura basica de un archivo de mapeo se parece a esto:
<?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="org.hibernate.tutorial.domain"> [...] </hibernate-mapping>

El DTD de Hibernate es sofisticado. Puedes usarlo para tareas de auto-completado de elementos y atributos XML en tu editor o IDE. Abrir el archivo DTD en tu editor de texto es la manera mas facil de tener una vision general de todos los elementos y atributos, de ver los valores por defecto, asi como ver algunos comentarios. Hibernate no carga el archivo DTD desde la web, si no que primero lo busca en el classpath de la aplicacion. El archivo DTD esta incluido en el archivo hibernate-core.jar (tambien esta incluido en el archivo hibernate3.jar si estas usando el paquete de distribucion).

Importante
Para acortar el codigo de los futuros ejemplos, omitiremos la declaracion del DTD. Por supuesto que en tu codigo debe aparecer siempre, ya que su inclusion no es opcional.

Entre las dos etiquetas hibernate-mapping incluye un elemento class . Todas las clases de entidades persistentes (de nuevo, podrian haber clases dependientes, las cuales veremos despues, que no son entidades de primera clase) necesitan un mapeo a una tabla en la base de datos SQL:

5 de 25

28/02/2010 22:34

Tutorial basico de Hibernate

http://www.davidmarco.es/tutoriales/hibernate-reference/

<hibernate-mapping package="org.hibernate.tutorial.domain"> <class name="Event" table="EVENTS"> </class> </hibernate-mapping>

Hasta ahora hemos indicado a Hibernate como persistir/leer objetos de la clase Event en/desde la tabla
EVENTS. Cada instancia esta ahora representada por una fila en dicha tabla. Ahora podemos continuar

mapeando la propiedad que representa la identidad de cada instancia. Como no queremos preocuparnos del manejo de este identificador, configuramos una estrategia de generacion de identidad en una columna de claves primarias:
<hibernate-mapping package="org.hibernate.tutorial.domain"> <class name="Event" table="EVENTS"> <id name="id" column="EVENT_ID"> <generator class="native"/> </id> </class> </hibernate-mapping>

El elemento id contiene la declaracion de la propiedad de identidad. El atributo de mapeo name="id" declara el nombre de la propiedad JavaBean e informa a Hibernate que debe usar los metodos getId() y setId() para acceder a ella. El atributo column informa a Hibernate que columna de la tabla EVENTS contiene el valor de la clave primaria. El elemento anidado generator especifica la estrategia de generacion de identidad (como son generados los valores de identidad?). En este caso hemos elegido native , que ofrece un nivel de portabilidad dependiendo del dialecto de base de datos configurado. Hibernate soporta que la identidad sea generada por la base de datos, globalmente unica, asi como asignada por la propia aplicacion. La generacion del valor de identidad es ademas una de las muchas extensiones de Hibernate, permitiendote acoplar tu propia estrategia.

Consejo
native no es considerada como la mejor estrategia en terminos de portabilidad.

Finalmente, necesitamos indicar a Hibernate como mapear las propiedades restantes de la entidad. Por defecto, ninguna propiedad de la entidad es considerada persistente:

6 de 25

28/02/2010 22:34

Tutorial basico de Hibernate

http://www.davidmarco.es/tutoriales/hibernate-reference/

<hibernate-mapping package="org.hibernate.tutorial.domain"> <class name="Event" table="EVENTS"> <id name="id" column="EVENT_ID"> <generator class="native"/> </id> <property name="date" type="timestamp" column="EVENT_DATE"/> <property name="title"/> </class> </hibernate-mapping>

De manera similar al elemento id, el atributo name del elemento property informa a Hibernate que metodo setter usar. En este caso, Hibernate buscara los metodos getDate(), setDate(), getTitle() y setTitle().

Nota
Por que el mapeo de la propiedad date incluye el atributo column pero no lo incluye el mapeo de title ? Sin el atributo column, Hibernate usa por defecto el nombre de la propiedad como nombre para la columna. Esto funciona para title , sin embargo date es una palabra reservada en muchas bases de datos por lo que necesitas mapear la propiedad date con un nombre diferente.

El mapeo de title tambien carece del atributo type . Los tipos de datos declarados y usados en los archivos de mapeo no son tipos de datos Java; tampoco son tipos de base de datos SQL. Son tipos llamados tipos de datos Hibernate , conversores que pueden trasladar desde tipos de datos Java a SQL y viceversa. De nuevo, Hibernate intentara determinar la conversion correcta y el tipo de datos por el mismo si el atributo type no se encuentra presente. En algunos casos esta deteccion automatica, que es determinada mediante reflexion, puede no resultar en el tipo que esperabas o necesitabas. Este es el caso con la propiedad date . Hibernate no puede conocer si la propiedad, que es del tipo java.util.Date , debe ser mapeada a una columna SQL del tipo
date , timestamp, o time . La informacion completa de fecha y hora es preservada mapeando la propiedad con

un convertidor timestamp.

Consejo
Hibernate determina el tipo de datos a usar mediante reflexion en el momento en que los archivos de mapeo son procesados. Esto puede tomar tiempo y recursos, por lo que si el rendimiento en el arranque es importante deberias considerar definir explicitamente todos los tipos a usar.

Guarda este archivo como src/main/resources/org/hibernate/tutorial/domain/Event.hbm.xml.

1.4 Configuracion de Hibernate


En este momento, deberias tener la clase persistente y su archivo de mapeo. Es el momento de configurar Hibernate. Primero, configuremos HSQLDB para funcionar en "modo servidor" (server mode)

7 de 25

28/02/2010 22:34

Tutorial basico de Hibernate

http://www.davidmarco.es/tutoriales/hibernate-reference/

Nota
Vamos a hacer esto para que los datos permanezcan entre ejecuciones.

Utilizaremos

el

plugin

'exec'

de

Maven

para

arrancar

el

servidor

HSQLDB

ejecutando:

mvn exec:java

-Dexec.mainClass="org.hsqldb.Server" -Dexec.args="-database.0 file:target/data/tutorial"

Veras como se inicia y asocia a un socket TCP/IP; alli es donde nuestra aplicacion conectara mas tarde. Si quieres comenzar el tutorial con una base de datos limpia, deten HSQLDB, elimina todos los archivos en el directorio target/data y arranca de nuevo HSQLDB. Hibernate conectara con la base de datos en nombre de tu aplicacion, por lo que necesita conocer como obtener conexiones. Para este tutorial usaremos un pool de conexiones (de manera opuesta a usar
javax.sql.DataSource ). HIbernate viene con soporte para dos pool de conexiones JDBC de terceros: c3p0 y

proxool.Sin embargo, usaremos el pool de conexiones integrado en Hibernate.

Atencion
El pool de conexiones integrado en Hibernate no esta pensado de ninguna manera para su uso en produccion, ya que carece de diversas caracteristicas disponibles en cualquier pool de conexiones decente.

Para la configuracion de Hibernate, podemos usar un sencillo archivo hibernate.properties , un mas sofisticado archivo hibernate.cfg.xml, o incluso una configuracion programatica completa. Muchos usuarios prefieren el archivo de configuracion XML:

8 de 25

28/02/2010 22:34

Tutorial basico de Hibernate

http://www.davidmarco.es/tutoriales/hibernate-reference/

<?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> <!-- Database connection settings --> <property name="connection.driver_class">org.hsqldb.jdbcDriver</property> <property name="connection.url">jdbc:hsqldb:hsql://localhost</property> <property name="connection.username">sa</property> <property name="connection.password"></property> <!-- JDBC connection pool (use the built-in) --> <property name="connection.pool_size">1</property> <!-- SQL dialect --> <property name="dialect">org.hibernate.dialect.HSQLDialect</property> <!-- 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> <!-- Drop and re-create the database schema on startup --> <property name="hbm2ddl.auto">update</property> <mapping resource="org/hibernate/tutorial/domain/Event.hbm.xml"/> </session-factory> </hibernate-configuration>

Nota
Observa que este archivo de configuracion define un DTD diferente

Has configurado un SessionFactory. SessionFactory es una factoria global reponsable de una base de datos en particular. Si dispones de varias bases de datos, deberias usar varias configuraciones <session-factory> en varios archivos de configuracion para simplificar el arranque. Los cuatro primeros elementos property contienen la configuracion necesaria para la conexion JDBC. El elemento contiene la configuracion necesaria para la conexion JDBC. El elemento property que hace referencia a 'dialect' especifica que variante de SQL tiene que generar Hibernate.

9 de 25

28/02/2010 22:34

Tutorial basico de Hibernate

http://www.davidmarco.es/tutoriales/hibernate-reference/

Consejo
En muchos casos, Hibernate es capaz de determinar correctamente el dialecto que debe usar.

El mantenimiento automatico de sesiones para contextos de persistencia de Hibernate es particularmente util en este contexto. La opcion hbm2ddl.auto activa la generacion automatica de esquemas en la base de datos. Esto puede ser desactivado eliminando la citada opcion de de configuracion, o redireccionado a un archivo con la ayuda de la tarea de Ant SchemaExport. Finalmente, aade el/los archivo(s) de mapeo para clases persistentes a la configuracion. Guarda este archivo como hibernate.cfg.xml dentro del directorio src/main/resources.

1.5 Construyendo con Maven


Ahora construiremos el tutorial con Maven. Por supuesto, necesitaras tener Maven instalado; esta disponible desde la pagina de descargas de Maven. Maven leera el archivo /pom.xml que hemos creado antes y sabra como realizar algunas tareas basicas del proyecto. Primero, ejecutemos la opcion compile para asegurarnos que podemos compilar todo lo hecho hasta ahora:
[hibernateTutorial]$ mvn compile [INFO] Scanning for projects... [INFO] -----------------------------------------------------------------------[INFO] Building First Hibernate Tutorial [INFO] task-segment: [compile] [INFO] -----------------------------------------------------------------------[INFO] [resources:resources] [INFO] Using default encoding to copy filtered resources. [INFO] [compiler:compile] [INFO] Compiling 1 source file to /home/steve/projects/sandbox/hibernateTutorial/target/classes [INFO] -----------------------------------------------------------------------[INFO] BUILD SUCCESSFUL [INFO] -----------------------------------------------------------------------[INFO] Total time: 2 seconds [INFO] Finished at: Tue Jun 09 12:25:25 CDT 2009 [INFO] Final Memory: 5M/547M [INFO] ------------------------------------------------------------------------

1.6 Puesta en marcha y clases de ayuda


Es el momento de leer y almacenar algunos objetos Event , pero primero tienes que completar la puesta en marcha con algo de codigo de infraestructura. Tienes que iniciar Hibernate construyendo un objeto global
org.hibernate.SessionFactory y almacenandolo en un lugar que sea de facil acceso para el codigo de la

aplicacion.

org.hibernate.SessionFactory

es

usado

para

obtener

instancias

de

org.hibernate.Session.

org.hibernate.Session representa una unidad de trabajo para un unico hilo de ejecucion,

o thread.

org.hibernate.SessionFactory es un objeto global de tipo thread-safe (varios hilos de ejecucion accediendo a el

al mismo tiempo son ejecutados en serie, nunca en paralelo) que es instanciado una sola vez. A continuacion crearemos una clase de ayuda HibernateUtil que se encargara de iniciar y hacer accesible
org.hibernate.SessionFactory de manera conveniente.

10 de 25

28/02/2010 22:34

Tutorial basico de Hibernate

http://www.davidmarco.es/tutoriales/hibernate-reference/

package org.hibernate.tutorial.util; import org.hibernate.SessionFactory; import org.hibernate.cfg.Configuration; public class HibernateUtil { private static final SessionFactory sessionFactory = buildSessionFactory(); private static SessionFactory buildSessionFactory() { try { // Create the SessionFactory from hibernate.cfg.xml return new Configuration().configure().buildSessionFactory(); } catch (Throwable ex) { // Make sure you log the exception, as it might be swallowed System.err.println("Initial SessionFactory creation failed." + ex); throw new ExceptionInInitializerError(ex); } } public static SessionFactory getSessionFactory() { return sessionFactory; } }

Guarda este codigo como src/main/java/org/hibernate/tutorial/util/HibernateUtil.java Esta clase no solo produce una referencia global org.hibernate.SessionFactory en su inicializador estatico; tambien oculta el hecho de que solo usa un singleton (objeto que es unico, no pueden generarse nunca dos instancias diferentes de el) estatico. Tambien podriamos haber buscado la referencia a
org.hibernate.SessionFactory mediante JNDI en un servidor de aplicaciones.

Si le das un nombre a org.hibernate.SessionFactory en tu configuracion, Hibernate intentara asociarlo a JNDI bajo ese nombre despues de haber sido construido. Una opcion mejor es usar un despliegue JMX y permitir a un contenedor con soporte JMX instanciar y asociar HibernateService a JNDI. Tales opciones avanzadas seran discutidas mas tarde. Ahora necesitas configurar un sistema de log. Hibernate usa 'commons logging' y ofrece dos opciones: log mediante Log4j y mediante JDK 1.4. Muchos desarrolladores prefieren Log4j: copia el archivo log4j.properties desde el directorio de la distribucion de Hibernate etc/ a tu directorio src, de manera que quede junto al archivo hibernate.cfg.xml que hemos creado previamente. Si prefieres tener una salida de log con informacion mas completa que la ofrecida en el ejemplo de configuracion, puedes cambiar los valores. Por defecto, solo los mensajes de inicio de Hibernate se muestran en stdout. La infraestructura del tutorial esta completa y ahora ya puedes comenzar a hacer trabajo real con Hibernate.

1.7 Leyendo y almacenando objetos


Ahora estamos listos para comenzar a hacer trabajo real con Hibernate. Comencemos escribiendo una clase
EventManager con un metodo main():

11 de 25

28/02/2010 22:34

Tutorial basico de Hibernate

http://www.davidmarco.es/tutoriales/hibernate-reference/

package org.hibernate.tutorial; import org.hibernate.Session; import java.util.*; import org.hibernate.tutorial.domain.Event; import org.hibernate.tutorial.util.HibernateUtil; public class EventManager { public static void main(String[] args) { EventManager mgr = new EventManager(); if (args[0].equals("store")) { mgr.createAndStoreEvent("My Event", new Date()); } HibernateUtil.getSessionFactory().close(); } private void createAndStoreEvent(String title, Date theDate) { Session session = HibernateUtil.getSessionFactory().getCurrentSession(); session.beginTransaction(); Event theEvent = new Event(); theEvent.setTitle(title); theEvent.setDate(theDate); session.save(theEvent); session.getTransaction().commit(); } }

En el metodo createAndStoreEvent() hemos creado un objeto Event y lo hemos manejado con Hibernate. En este punto, Hibernate se preocupa de las operaciones SQL por nosotros y ejecuta una operacion INSERT en la base de datos. La clase org.hibernate.Session esta diseada para representar una unica unidad de trabajo a ser realizada. Por ahora mantendremos las cosas simples y asumiremos una granularidad uno-a-uno entre el objeto org.hibernate.Session de Hibernate y una transaccion de base de datos. Para proteger a nuestro codigo del sistema subyacente de transacciones usaremos la API org.hibernate.Transaction. En este caso en particular estamos usando semantica transaccional basada en JDBC, pero tambien podria funcionar mediante JTA. Que es lo que hace sessionFactory.getCurrentSession()? Para empezar, puedes llamarlo cuantas veces quieras y desde donde quieras una vez que consigas un objeto
org.hibernate.SessionFactory.

El

metodo

getCurrentSession() siempre devuelve la unidad de trabajo "actual". Recuerda que cambiamos la opcion de

configuracion para este mecanismo a "thread" en el archivo src/main/resources/hibernate.cfg.xml? Debido a este ajuste, el contexto de la unidad de trabajo actual esta asociado al thread actual , que es el que ejecuta la aplicacion.

12 de 25

28/02/2010 22:34

Tutorial basico de Hibernate

http://www.davidmarco.es/tutoriales/hibernate-reference/

Importante
Hibernate ofrece tres metodos para el seguimiento de la sesion actual. El metodo basado en "thread" no es el deseado para uso en produccion; es unicamente util para prototipos y tutoriales como este. El seguimiento de la sesion actual es discutido en mas detalle mas tarde.

Una sesion org.hibernate.Session comienza cuando la primera llamada a getCurrentSession() es hecha por el thread actual. Entonces, es asociada por Hibernate al thread actual. Cuando la transaccion termina, ya sea aceptada (commit) o cancelada (rollback), Hibernate desasocia automaticamente la sesion org.hibernate.Session del thread y la cierra por ti. Si llamas de nuevo a getCurrentSession() , obtienes una nueva sesion org.hibernate.Session y puedes comenzar una nueva unidad de trabajo. Hablando del alcance de la unidad de trabajo, deberia org.hibernate.Session usarse para ejecutar una o varias operaciones de base de datos? El ejemplo anterior usa un objeto org.hibernate.Session para una unica operacion. Sin embargo, esto es pura coincidencia; el ejemplo no es lo suficientemente complejo para mostrar otra opcion. El alcance de org.hibernate.Session puede es flexible, pero nunca debes disear tu aplicacion para usar un nuevo objeto org.hibernate.Session por cada operacion de base de datos. Aunque esto es lo que ocurre en los siguientes ejemplos, considera que sesion-por-operacion es un anti-pattern (un diseo contrario a las buenas practicas de programacion). Una aplicacion web real es mostrada mas tarde en el tutorial, la cual te ayudara a ilustrar mejor este concepto. El ejemplo anterior tambien ha evitado cualquier manejo de errores asi como cancelaciones de la transaccion en caso de que los primeros hubiera ocurrido. Para ejecutar el codigo anterior, tenemos que hacer uso de la opcion 'exec' de Maven para llamar a nuestra clase con los ajustes de classpath necesarios:
mvn exec:java -Dexec.mainClass="org.hibernate.tutorial.EventManager" -Dexec.args="store"

Nota
Tal vez necesites realizar primero una llamada a mvn compile.

Deberias ver a Hibernate arrancando y, dependiendo de tu configuracion, un monton de salida de log. Cerca del final, se mostrara la siguiente linea:
[java] Hibernate: insert into EVENTS (EVENT_DATE, title, EVENT_ID) values (?, ?, ?)

Esta es la secuencia SQL INSERT ejecutada por Hibernate. Para listar eventos, aadimos el siguiente codigo al metodo 'main':

13 de 25

28/02/2010 22:34

Tutorial basico de Hibernate

http://www.davidmarco.es/tutoriales/hibernate-reference/

if (args[0].equals("store")) { mgr.createAndStoreEvent("My Event", new Date()); } else if (args[0].equals("list")) { List events = mgr.listEvents(); for (int i = 0; i < events.size(); i++) { Event theEvent = (Event) events.get(i); System.out.println( "Event: " + theEvent.getTitle() + " Time: " + theEvent.getDate() ); } }

Asi mismo, un nuevo metodo listEvents() es tambien aadido:


private List listEvents() { Session session = HibernateUtil.getSessionFactory().getCurrentSession(); session.beginTransaction(); List result = session.createQuery("from Event").list(); session.getTransaction().commit(); return result; }

Aqui estamos usando una solicitud Hibernate Query Language (HQL) para leer todos los objetos Event desde la base de datos. Hibernate generara las sentencias SQL adecuadas, las enviara a la base de datos y creara objetos Event con los datos obtenidos. HQL te permite crear consultas mucho mas complejas. Ahora podemos probar nuestra nueva funcionalidad, de nuevo usando la opcion 'exec' de Maven:
mvn exec:java -Dexec.mainClass="org.hibernate.tutorial.EventManager" -Dexec.args="list"

Parte 2 - Mapeo de asociaciones


Hasta ahora hemos mapeado una unica clase persistente en isolacion a la base de datos. Ampliemos un poco el mapeo y aadamos algunas asociaciones entre clases. Aadiremos personas a la aplicacion y almacenaremos una lista de eventos en los cuales cada persona puede participar.

2.1 Mapeando la clase Persona


La primera version de la clase Person seria algo asi:

14 de 25

28/02/2010 22:34

Tutorial basico de Hibernate

http://www.davidmarco.es/tutoriales/hibernate-reference/

package org.hibernate.tutorial.domain; public class Person { private Long id; private int age; private String firstname; private String lastname; public Person() {} // Accessor methods for all properties, private setter for 'id' }

Guarda el codigo anterior en un archivo llamado src/main/java/org/hibernate/tutorial/domain/Person.java A continuacion, crea un nuevo archivo de mapeo con el nombre

src/main/resources/org/hibernate/tutorial/domain/Person.hbm.xml <hibernate-mapping package="org.hibernate.tutorial.domain"> <class name="Person" table="PERSON"> <id name="id" column="PERSON_ID"> <generator class="native"/> </id> <property name="age"/> <property name="firstname"/> <property name="lastname"/> </class> </hibernate-mapping>

Finalmente, aade el mapeo a la configuracion de Hibernate:


<mapping resource="events/Event.hbm.xml"/> <mapping resource="events/Person.hbm.xml"/>

Crea una asociacion entre estas dos entidades. Las personas pueden participar en enventos, y los eventos tienen participantes. Las cuestiones de diseo con las que tienes que tratar son: direccionalidad, multiplicidad, y comportamiento de la coleccion.

2.2 Una asociacion unidireccional basada en Set


Aadiendo una coleccion de eventos a la clase Person, puedes navegar facilmente por todos los eventos de una persona en particular, sin ejecutar ninguna consulta explicita - llamando a Person#getEvents . Asociaciones que representan multiples valores son representadas en Hibernate por uno de los contratos del Java Collection Framework; aqui hemos elegido java.util.Set porque no queremos que la coleccion contenga elementos duplicados y porque el orden en que esten ordenados no es relevante para nuestros ejemplos:

15 de 25

28/02/2010 22:34

Tutorial basico de Hibernate

http://www.davidmarco.es/tutoriales/hibernate-reference/

public class Person { private Set events = new HashSet(); public Set getEvents() { return events; } public void setEvents(Set events) { this.events = events; } }

Antes de mapear esta asociacion, consideremos como sera desde el otro lado. Podemos mantener esta asociacion unidireccional o crear otra coleccion en la clase Event, si es que queremos ser capaces de navegar en ambas direcciones. Esto no es necesario desde una perspectiva funcional. Siempre puedes ejecutar una consulta explicita para obtener los participantes para un evento en particular. Esta es una decision de diseo que te dejamos a ti, pero lo que queda claro de esta discursion es la multiplicidad de la asociacion: "muchos" valores en ambos lados forman una asociacion de tipo many-to-many (muchos-a-muchos). Por lo tanto, usamos un mapeo many-to-many de Hibernate:
<class name="Person" table="PERSON"> <id name="id" column="PERSON_ID"> <generator class="native"/> </id> <property name="age"/> <property name="firstname"/> <property name="lastname"/> <set name="events" table="PERSON_EVENT"> <key column="PERSON_ID"/> <many-to-many column="EVENT_ID" class="Event"/> </set> </class>

Hibernate soporta un amplio rango de mapeo de colecciones, siendo set el mas comun. Para una asociacion de tipo many-to-many, o relacion entre entidades n:m, se requiere una tabla de asociacion. Cada fila en esta tabla representa un enlace entre una persona y un evento. El nombre de la tabla es declarado usando el atributo table del elemento set . El nombre de la columna identificadora de la asociacion para el lado las personas, es definido con el elemento key; el nombre de la columna identificadora de la asociacion para el lado de los eventos con el atributo column del elemento many-to-many. Tambien tienes que informar a Hibernate de la clase de objetos que almacena tu coleccion. El esquema de base de datos para este mapeo es el siguiente:

16 de 25

28/02/2010 22:34

Tutorial basico de Hibernate

http://www.davidmarco.es/tutoriales/hibernate-reference/

_____________ | | EVENTS | | | |

__________________ | PERSON_EVENT | | | PERSON _____________ | |

|_____________| | | *EVENT_ID | | |

|__________________| | | |

|_____________| | | | | | |

|<---->| *EVENT_ID | *PERSON_ID

EVENT_DATE | TITLE |

|<---->| *PERSON_ID | | | AGE FIRSTNAME LASTNAME

|__________________|

|_____________|

|_____________|

2.3 Trabajando con la asociacion


Ahora vamos a traer varias personas y eventos, y vamos a juntarlos en un nuevo metodo que crearemos en
EventManager: private void addPersonToEvent(Long personId, Long eventId) { Session session = HibernateUtil.getSessionFactory().getCurrentSession(); session.beginTransaction(); Person aPerson = (Person) session.load(Person.class, personId); Event anEvent = (Event) session.load(Event.class, eventId); aPerson.getEvents().add(anEvent); session.getTransaction().commit(); }

Despues de obtener un objeto Person y un objeto Event , modificamos la colecion utilizando sus metodos tipicos. No hay una llamada explicita a update() or save(); Hibernate detecta automaticamente que la coleccion ha sido modificada y necesita ser actualizada. Esto se conoce como comprobacion automatica de datos obsoletos (en el original ingles se utiliza el termino 'dirty', que significa suciedad, en lugar de 'obsoleto'. En espaol la traduccion literal de la frase original no seria aclaratoria). Tambien puedes intentar modificar las propiedades correspondientes al nombre o a la fecha de cualquiera de estos objetos. Mientras esten en estado persistente, osea, ligados a una instancia activa de org.hibernate.Session, Hibernate monitorea cualquier cambio y ejecuta instancias SQL de manera totalmente transparente para el usuario. El proceso de sincronizacion entre es estado de la memoria y la base de datos, realizado normalmente al final de la unidad de trabajo, es llamado flushing (descargar). En nuestro codigo, la unidad de trabajo termina aceptando (commit) o cancelando (rollback) la transaccion en la base de datos. Puedes obtener personas y eventos en diferentes unidades de trabajo. O puedes modificar un objeto fuera del alcance de org.hibernate.Session, cuando no esta en estado persistente (si ya fue persistido anteriormente, este estado es llamado separado, o 'detached'). Incluso puede modificar una coleccion cuando esta separada:

17 de 25

28/02/2010 22:34

Tutorial basico de Hibernate

http://www.davidmarco.es/tutoriales/hibernate-reference/

private void addPersonToEvent(Long personId, Long eventId) { Session session = HibernateUtil.getSessionFactory().getCurrentSession(); session.beginTransaction(); Person aPerson = (Person) session .createQuery("select p from Person p left join fetch p.events where p.id = :pid") .setParameter("pid", personId) .uniqueResult(); // Eager fetch the collection so we can use it detached Event anEvent = (Event) session.load(Event.class, eventId); session.getTransaction().commit(); // End of first unit of work aPerson.getEvents().add(anEvent); // aPerson (and its collection) is detached // Begin second unit of work Session session2 = HibernateUtil.getSessionFactory().getCurrentSession(); session2.beginTransaction(); session2.update(aPerson); // Reattachment of aPerson session2.getTransaction().commit(); }

La llamada a update convierte de nuevo la entidad separado en persistida, asociandola con una nueva unidad de trabajo, por lo que cualquier modificacion que hagas en ella mientras estaba separada puede ser guardada en la base de datos. Esto incluye cualquier modificacion (adiciones/eliminaciones) que hagas en una coleccion de dicha entidad. No se ha usado mucho en nuestro ejemplo, pero es un concepto importante que puedes incorporar en tu propia aplicacion. Completa este ejercicio aadiendo una nueva accion al metodo main de EventManager e invocalo desde la linea de comandos. Si necesitas los identificadores de una persona y un evento, el metodo
save() los devuelve (tal vez tengas que modificar algunos de los metodos anteriores para devolver dicho

identificador):
else if (args[0].equals("addpersontoevent")) { Long eventId = mgr.createAndStoreEvent("My Event", new Date()); Long personId = mgr.createAndStorePerson("Foo", "Bar"); mgr.addPersonToEvent(personId, eventId); System.out.println("Added person " + personId + " to event " + eventId); }

El codigo anterior es un ejemplo de una asociacion entre dos clases igualmente importantes: dos entidades. Como se ha mencionado anteriormente, hay otras clases y tipos en un modelo tipico, que son considerados "menos importantes". Algunos ya los has visto, como int o java.lang.String. Llamamos a esas clases tipos con valor, y sus instancias dependen de una entidad en concreto. Las instancias de tipos con valor no tienen identidad, ni tampoco son compartidos entre entidades. Dos personas no pueden hacer referencia al mismo objeto firstname , incluso aunque tengan el mismo nombre. Tipos con valor no solo pueden ser encontrados en el JDK , si no que tambien puedes escribir tus propias clases dependientes como Address o MonetaryAmount . De hecho, en una aplicacion Hibernate todas las clases del JDK son consideradas tipos con valor. Tambien puedes disear una coleccion de tipos con valor. Esto es conceptualmente diferente de una coleccion

18 de 25

28/02/2010 22:34

Tutorial basico de Hibernate

http://www.davidmarco.es/tutoriales/hibernate-reference/

de referencias a otras entidades, pero parecen casi iguales cuando las vemos en Java.

2.4 Colecciones de valores


Aadamos una coleccion de direcciones de correo electronico a la entidad Person. Esta sera representada como una instancia de java.util.Set que contendra instancias de java.lang.String:
private Set emailAddresses = new HashSet(); public Set getEmailAddresses() { return emailAddresses; } public void setEmailAddresses(Set emailAddresses) { this.emailAddresses = emailAddresses; }

El mapeo para este Set es el siguiente:


<set name="emailAddresses" table="PERSON_EMAIL_ADDR"> <key column="PERSON_ID"/> <element type="string" column="EMAIL_ADDR"/> </set>

La diferencia en comparacion con el mapeo anterior es el uso de element , el cual indica a Hibernate que la coleccion no contiene referencias a otras entidades, si no una coleccion cuyos elementos son tipos con valor, especificamente del tipo string. El nombre con la primera letra en minusculas indica el mapeo de un tipo/conversor de Hibernate. De nuevo, el atributo table dentro del elemento set determina el nombre de la tabla donde almacenar la coleccion. El elemento key define el nombre de la columna de claves foraneas en la tabla que contiene la coleccion. El atributo column en el elemento element define el nombre de la columna donde los valores de las direcciones de correo electronico seran almacenadas. Aqui esta el esquema actualizado:

_____________ | | EVENTS | | | |

__________________ | PERSON_EVENT | | | PERSON _____________ | | | ___________________ |

|_____________| | | *EVENT_ID | | |

|__________________| | | |

| PERSON_EMAIL_ADDR | |___________________| | *PERSON_ID *EMAIL_ADDR | | |

|_____________| | |

|<--->| *EVENT_ID | *PERSON_ID

EVENT_DATE | TITLE |

|<--->| *PERSON_ID | | | AGE FIRSTNAME LASTNAME

|<--->| | | | |

|__________________|

|_____________|

|___________________|

|_____________|

Puedes ver que la clave primaria de la tabla que almacena la coleccion es de hecho una clave compuesta que utiliza ambas columnas. Esto tambien implica que no pueden existir direcciones de correo electronico duplicadas por persona, que es exactamente la semantica que necesitamos para una coleccion de tipo set en Java. Ahora puedes intentar aadir elecmentos a esta coleccion, exactamente como lo hicimos antes asociando

19 de 25

28/02/2010 22:34

Tutorial basico de Hibernate

http://www.davidmarco.es/tutoriales/hibernate-reference/

personas y eventos. Es el mismo tipo de codigo en Java, utilizando metodos getter y setter:
private void addEmailToPerson(Long personId, String emailAddress) { Session session = HibernateUtil.getSessionFactory().getCurrentSession(); session.beginTransaction(); Person aPerson = (Person) session.load(Person.class, personId); // adding to the emailAddress collection might trigger a lazy load of the collection aPerson.getEmailAddresses().add(emailAddress); session.getTransaction().commit(); }

Esta vez no utilizamos una consulta de tipo fetch para inicializar la coleccion. Monitorea el log de SQL e intenta optimizarla con una lectura temprana de datos (eager fetch).

2.5 Asociaciones bidireccionales


A continuacion mapearemos una asociacion bidireccional. Haremos que la asociacion sea manejable entre personas y eventos en ambos sentidos. El esquema de la base de datos no cambia, por lo que seguiras teniendo una multiplicidad muchos-a-muchos.

Nota
Una base de datos relacional es mas flexible que un lenguaje de programacion en red, ya que no necesita una direccion de navegacion entre asociaciones; los datos pueden ser vistos y recuperados de cualquier manera posible.

Primero, aade una coleccion de participantes en la clase Event:


private Set participants = new HashSet(); public Set getParticipants() { return participants; } public void setParticipants(Set participants) { this.participants = participants; }

Ahora mapea este lado de la asociacion en Event.hbm.xml.


<set name="participants" table="PERSON_EVENT" inverse="true"> <key column="EVENT_ID"/> <many-to-many column="PERSON_ID" class="events.Person"/> </set>

Estos son mapeos normales de tipo set en ambos archivos. Fijate que los nombres de las columnas en key y
many-to-many se intercambian en ambos archivos de mapeo. El aadido mas importante es el atributo inverse="true" en el elemento set del mapeo de la coleccion Event .

El significado de esto es que Hibernate deberia utilizar el otro lado, en este caso la clase Person , cuando

20 de 25

28/02/2010 22:34

Tutorial basico de Hibernate

http://www.davidmarco.es/tutoriales/hibernate-reference/

necesita buscar informacion acerca de un enlace entre las dos clases. Esto es muy sencillo de comprender una vez que ves como es creado el enlace bidireccional entre nuestras dos entidades.

2.6 Trabajando con enlaces bidireccionales


Primero, ten en mente que Hibernate no afecta a la semantica normal de Java. Como hemos creado anteriormente un enlace entre Person y Event en el ejemplo unidireccional? Aadiste una instancia de Event a la coleccion que almacena eventos en Person. Si quieres hacer este enlace bidireccional, tienes que hacer lo mismo en el otro lado de la asociacion aadiendo una referencia de tipo Person a la coleccion que tenemos en
Event . Este proceso de "ajustar los enlaces en ambos lados" es absolutamente necesario con enlaces

bidireccionales. Muchos desarrolladores programan defensivamente y crean metodos de mantenimiento de enlaces para ajustar correctamente ambos lados (por ejemplo, en Person):
protected Set getEvents() { return events; } protected void setEvents(Set events) { this.events = events; } public void addToEvent(Event event) { this.getEvents().add(event); event.getParticipants().add(this); } public void removeFromEvent(Event event) { this.getEvents().remove(event); event.getParticipants().remove(this); }

Los metodos get y set de la coleccion son ahora de tipo 'protected'. Esto permite a las clases en el mismo paquete y las subclases seguir accediendo a dichos metodos, pero previene que todo el mundo pueda alterar la coleccion directamente. Repite este paso en la coleccion del otro lado. Y que hay del atributo de mapeo inverse? Para ti, y para Java, un enlace bidireccional es simplemente una manera de ajustar las referencias en ambos lados de forma correcta. Hibernate, sin embargo, no tiene la informacion suficiente para organizar correctamente las sentencias SQL INSERT y UPDATE (para evitar violaciones de uso). Haciendo uno de los lados de la asociacion inverse informa a Hibernate que considere ese lado como un espejo del otro lado. Esto es todo lo necesario para que Hibernate pueda resolver cualquier problema que surja en el momento de transformar un modelo de navegacion direccional en un esquema SQL para la base de datos. Las reglas son sencillas: todas las asociaciones bidireccionales necesitan que un lado sea declarado inverse . En una asociacion uno-a-muchos este tiene que ser el lado 'muchos', y en una asociacion muchos-a-muchos puedes elegir cualquiera de los lados.

Parte 3 - La aplicacion web EventManager


Una aplicacion web Hibernate utiliza objetos Session y Transaction casi igual que una aplicacion independiente. Sin embargo, algunos patrones de diseo son utiles. Por ejemplo, puedes escribir un EventManagerServlet . Este servlet puede listar todos los eventos almacenados en la base de datos, y ofrece un formulario HTML para introducir nuevos eventos.

21 de 25

28/02/2010 22:34

Tutorial basico de Hibernate

http://www.davidmarco.es/tutoriales/hibernate-reference/

3.1 Escribiendo el servlet basico


Primero necesitamos crear nuestro servlet de procesamiento basico. Puesto que este servlet solo maneja solicitudes HTTP de tipo GET, solo implementaremos el metodo doGet():
package org.hibernate.tutorial.web; // Imports public class EventManagerServlet extends HttpServlet { protected void doGet( HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { SimpleDateFormat dateFormatter = new SimpleDateFormat( "dd.MM.yyyy" ); try { // Begin unit of work HibernateUtil.getSessionFactory().getCurrentSession().beginTransaction(); // Process request and render page... // End unit of work HibernateUtil.getSessionFactory().getCurrentSession().getTransaction().commit(); } catch (Exception ex) { HibernateUtil.getSessionFactory().getCurrentSession().getTransaction().rollback(); if ( ServletException.class.isInstance( ex ) ) { throw ( ServletException ) ex; } else { throw new ServletException( ex ); } } } }

Guarda este servlet como src/main/java/org/hibernate/tutorial/web/EventManagerServlet.java El patron de diseo aplicado aqui se llama una-sesion-por-solicitud. Cuando una solicitud alcanza el servlet, un nueva sesion de tipo Session es abierta a traves de la primera llamada al metodo getCurrentSession() de
SessionFactory. Una transaccion de base de datos es entonces iniciada. Todos los accesos a datos ocurren

dentro de dicha transaccion independientemente de si los datos son leidos o escritos. no use el modo 'autocommit' en tus aplicaciones. No uses un objeto Session para cada operacion de base de datos. Usa solamente una que alcance a la solicutud HTTP completa. Usa getCurrentSession(), de manera que sea automaticamente asociada al hilo de ejecucion actual. A continuacion, las posibles acciones de la solicitud son procesadas y la respuesta HTML es formada. En breve iremos a esa parte.

22 de 25

28/02/2010 22:34

Tutorial basico de Hibernate

http://www.davidmarco.es/tutoriales/hibernate-reference/

Finalmente, la unidad de trabajo termina cuando el procesamiento y la formacion de la respuesta estan completadas. Si ocurriera cualquier problema durante estas dos fases, se lanzaria una excepcion y la transaccion de base de datos seria cancelada y sus cambios desechos. Esto completa el patron
una-sesion-por-solicitud. En lugar de escribir codigo para demarcar la transaccion en cada servlet, tambien

puedes escribir un filtro servlet. Mira en el sitio web de Hibernate y en su Wiki si quieres mas informacion sobre este patro, llamado Abrir Sesion en la Vista. Lo necesitaras tan pronto como consideres formar la vista mediante JSP, en lugar de mediante servlets.

3.2 Procesando la solicitud y formando la pagina de respuesta


Ahora puedes implementar el procesamiento de la solicitud y formar la pagina de respuesta.
// Write HTML header PrintW riter out = response.getW riter(); out.println("<html><head><title>Event Manager</title></head><body>"); // Handle actions if ( "store".equals(request.getParameter("action")) ) { String eventTitle = request.getParameter("eventTitle"); String eventDate = request.getParameter("eventDate"); if ( "".equals(eventTitle) || "".equals(eventDate) ) { out.println("<b><i>Please enter event title and date.</i></b>"); } else { createAndStoreEvent(eventTitle, dateFormatter.parse(eventDate)); out.println("<b><i>Added event.</i></b>"); } } // Print page printEventForm(out); listEvents(out, dateFormatter); // W rite HTML footer out.println("</body></html>"); out.flush(); out.close();

Este estilo de escribir codigo, mezclando Java y HTML, no es nada escalable en una aplicacion mas compleja (ten en cuenta que solo se estan ilustrando conceptos basicos de Hibernate en este tutorial). El codigo imprime una tanto una cabecera como un pie de pagina HTML. Dentro de esta pagina, se muestran un formulario HTML para introducir eventos y una lista de todos los eventos almacenados en la base de datos. El primer metodo es muy trivial, y solo produce salida HTML:

23 de 25

28/02/2010 22:34

Tutorial basico de Hibernate

http://www.davidmarco.es/tutoriales/hibernate-reference/

private void printEventForm(PrintWriter out) { out.println("<h2>Add new event:</h2>"); out.println("<form>"); out.println("Title: <input name='eventTitle' length='50'/><br/>"); out.println("Date (e.g. 24.12.2009): <input name='eventDate' length='10'/><br/>"); out.println("<input type='submit' name='action' value='store'/>"); out.println("</form>"); }

El metodo listEvents() usa un objeto Session asociado al hilo de ejecucion actual para ejecutar una consulta a la base de datos:
private void listEvents(PrintWriter out, SimpleDateFormat dateFormatter) { List result = HibernateUtil.getSessionFactory() .getCurrentSession().createCriteria(Event.class).list(); if (result.size() > 0) { out.println("<h2>Events in database:</h2>"); out.println("<table border='1'>"); out.println("<tr>"); out.println("<th>Event title</th>"); out.println("<th>Event date</th>"); out.println("</tr>"); Iterator it = result.iterator(); while (it.hasNext()) { Event event = (Event) it.next(); out.println("<tr>"); out.println("<td>" + event.getTitle() + "</td>"); out.println("<td>" + dateFormatter.format(event.getDate()) + "</td>"); out.println("</tr>"); } out.println("</table>"); } }

Por ultimo, la accion store es redirigida al metodo createAndStoreEvent(), el cual tambien usa el objeto Session del hilo de ejecucion actual:
protected void createAndStoreEvent(String title, Date theDate) { Event theEvent = new Event(); theEvent.setTitle(title); theEvent.setDate(theDate); HibernateUtil.getSessionFactory() .getCurrentSession().save(theEvent); }

The servlet is now complete. A request to the servlet will be processed in a single Session and Transaction. As earlier in the standalone application, Hibernate can automatically bind these objects to the current thread of execution. This gives you the freedom to layer your code and access the SessionFactory in any way you like. Usually you would use a more sophisticated design and move the data access code into data access objects (the DAO pattern). See the Hibernate Wiki for more examples.

24 de 25

28/02/2010 22:34

Tutorial basico de Hibernate

http://www.davidmarco.es/tutoriales/hibernate-reference/

de separar en capas tu codigo y acceder a SessionFactory de la manera que quieras. Normalmente usarias un diseo mas sofisticado y moverias el codigo de acceso al interior de un objeto de acceso a datos (patron de diseo DAO). En el Wiki de Hibernate puedes encontrar mas ejemplos.

3.3 Desplegando y probando


Para desplegar esta aplicacion y probarla, necesitamos crear un ARchivo Web (WAR). Primero debemos definir un descriptor WAR en el archivo src/main/webapp/WEB-INF/web.xml:
<?xml version="1.0" encoding="UTF-8"?> <web-app version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"> <servlet> <servlet-name>Event Manager</servlet-name> <servlet-class>org.hibernate.tutorial.web.EventManagerServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>Event Manager</servlet-name> <url-pattern>/eventmanager</url-pattern> </servlet-mapping> </web-app>

Para construir y desplegar la aplicacion ejecuta el comando mvn package en el directorio del proyecto, y copia el archivo resultante hibernate-tutorial.war en el directorio webapps de tu instalacion de Tomcat.

Nota
Si no tienes Tomcat instalado, descargalo desde http://tomcat.apache.org/ y sigue las instrucciones de instalacion que encontraras en la misma web. Nuestra aplicacion no requiere cambios en la configuracion estandar de Tomcat.

Con la aplicacion desplegada y Tomcat ejecutandose, accede a la aplicacion mediante la direccion


http://localhost:8080/hibernate-tutorial/eventmanager. Asegurate de mirar el log de Tomcat para ver que

Hibernate se inicia cuando la primera solicitud alcanza tu servlet (el inicializador estatico en HibernateUtil es llamado) y de obtener una salida detallada si cualquier excepcion ocurriera.

Resumen
Este tutorial ha cubierto los aspectos basicos sobre como escribir una sencilla aplicacion Hibernate independiente, asi como una pequea aplicacion web. Tanto en el sitio web de Hibernate como en el sitio web del traductor hay disponibles mas tutoriales.

Copyright 2004 Red Hat Middleware, LLC. Traducido por David Marco

25 de 25

28/02/2010 22:34

También podría gustarte