Vous êtes sur la page 1sur 37

Tutorial basico de Hibernate

por Gavin King, ChristianBauer,MaxRydahlAndersen,EmmanuelBernard, y SteveEbersole 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 directorioproject/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.

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.
<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 <dependency> <groupId>javassist</groupId> <artifactId>javassist</artifactId> </dependency> </dependencies> </project> gives you a choice of bytecode providers

between cglib and javassist -->

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 todaslas 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, todos los archivos del directorio lib/required asi como

todos

los

archivos

de

los

directorios

lib/bytecode/cglibo

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. 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-mapping3.0.dtd"> <hibernate-mapping package="org.hibernate.tutorial.domain"> [...] </hibernate-mapping>

El DTD de Hibernate es sofisticado. Puedes usarlo para tareas de autocompletado 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 hibernatecore.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:


<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 Eventen/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 idcontiene 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
nativeno 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:
<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


propertyinforma 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 dateincluye 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
typeno

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, otime. 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)

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/datay 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 archivohibernate.cfg.xml, o incluso

una configuracion programatica completa. Muchos usuarios prefieren el archivo de configuracion XML:
<?xml version='1.0' encoding='utf-8'?> <!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-configuration3.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</pro perty> <!-- 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 propertycontienen

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.

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

opcionhbm2ddl.autoactiva 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.xmldentro

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.SessionFactoryy 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.Sessionrepresenta 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.
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 Configuration().configure().buildSessionFactory(); } catch (Throwable ex) { // Make sure you log the exception, as it might be swallowed System.err.println("Initial failed." + ex); throw new ExceptionInInitializerError(ex); } } public static SessionFactory getSessionFactory() { return sessionFactory; } } SessionFactory creation new

Guarda

este

codigo

como

src/main/java/org/hibernate/tutorial/util/HibernateUtil.java

Esta

clase

no

solo

produce

una

referencia

globalorg.hibernate.SessionFactoryen 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 mediante buscado JNDI en la un referencia servidor de

aorg.hibernate.SessionFactory 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 Hibernateetc/ a tu directorio src, de manera que quede junto al archivo hibernate.cfg.xmlque 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():
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.beginTransaction(); Event theEvent = new Event(); theEvent.setTitle(title); theEvent.setDate(theDate); session.save(theEvent); session.getTransaction().commit(); } } session = HibernateUtil.getSessionFactory().getCurrentSession();

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 Debido a el este archivo ajuste, el

src/main/resources/hibernate.cfg.xml?

contexto de la unidad de trabajo actual esta asociado al thread actual , que es el que ejecuta la aplicacion.

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.Sessiondel thread y la cierra por ti. Si llamas de nuevo a getCurrentSession(), obtienes una nueva sesion org.hibernate.Sessiony puedes comenzar una nueva unidad de trabajo. Hablando del alcance de la unidad de trabajo, deberia

org.hibernate.Sessionusarse 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-operaciones un antipattern (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:
Dexec.args="store" mvn exec:java -

Dexec.mainClass="org.hibernate.tutorial.EventManager"-

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':
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.beginTransaction(); session = HibernateUtil.getSessionFactory().getCurrentSession();

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:
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:
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


setel 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
columndel elemento many-to-many. Tambien tienes que informar

Hibernate de la clase de objetos que almacena tu coleccion. El esquema de base de datos para este mapeo es el siguiente:

_____________ | | | | *EVENT_ID | | TITLE EVENTS | | | EVENT_DATE | |

__________________ | | | | *PERSON_ID PERSON_EVENT | | | | | | | | | | AGE FIRSTNAME LASTNAME PERSON _____________ | | | | | | |

|_____________|

|__________________|

|_____________|

|<---->| *EVENT_ID

|<---->| *PERSON_ID

|__________________|

|_____________|

|_____________|

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.beginTransaction(); session = HibernateUtil.getSessionFactory().getCurrentSession();

Person personId);

aPerson

(Person)

session.load(Person.class,

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

necesita ser

actualizada.

Esto

se conoce

comocomprobacion 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:
private void addPersonToEvent(Long personId, Long eventId) { Session session.beginTransaction(); Person aPerson = (Person) session session = HibernateUtil.getSessionFactory().getCurrentSession();

.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); collection) is detached // Begin second unit of work Session session2.beginTransaction(); session2.update(aPerson); // Reattachment of aPerson session2.getTransaction().commit(); } session2 = // aPerson (and its

HibernateUtil.getSessionFactory().getCurrentSession();

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 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.Setque 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 tipostring. El nombre con la primera letra en minusculas indica el mapeo de un tipo/conversor de Hibernate. De nuevo, el atributo tabledentro del elemento set determina el nombre de la tabla donde almacenar la coleccion. El elemento keydefine 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:

_____________ | | | |_____________| PERSON_EMAIL_ADDR | | | *EVENT_ID | | | EVENT_DATE | | | | TITLE | EVENTS | | ___________________

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

|__________________| |

|_____________| | |

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

|<--->| *PERSON_ID | AGE

|<--->| | |

*PERSON_ID *EMAIL_ADDR

|__________________|

|_____________| |___________________| |

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

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

Estos son mapeos normales de tiposet 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 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
INSERTy UPDATE (para evitar violaciones de uso). Haciendo uno de los

lados de la asociacion inverseinforma a Hibernate que considere ese lado como un espejodel 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 Transactioncasi igual que una aplicacion independiente. Sin embargo, algunos patrones de diseo son utiles. Este Por servlet ejemplo, puede puedes todos escribir los un

EventManagerServlet.

listar

eventos

almacenados en la base de datos, y ofrece un formulario HTML para introducir nuevos eventos.

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 IOException { SimpleDateFormat "dd.MM.yyyy" ); try {

response)

throws

ServletException,

dateFormatter

new

SimpleDateFormat(

// Begin unit of work HibernateUtil.getSessionFactory().getCurrentSession().beginTransacti on(); // 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
Sessiones

abierta

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 'auto-commit' en tus aplicaciones. Nouses 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. 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 PrintWriter out = response.getWriter(); 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 date.</i></b>"); } else { createAndStoreEvent(eventTitle, dateFormatter.parse(eventDate)); out.println("<b><i>Added event.</i></b>"); } } // Print page printEventForm(out); listEvents(out, dateFormatter); // Write HTML footer out.println("</body></html>"); out.flush(); out.close(); enter event title and

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

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
SessionFactoryin 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. de separar en capas tu codigo y acceder a SessionFactoryde 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 archivosrc/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> <servletclass>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 resultantehibernatetutorial.war en el directoriowebapps de tu instalacion de Tomcat.

Nota
Si no tienes Tomcat instalado, descargalo

desdehttp://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 Hibernatecomo en el sitio web del traductor hay disponibles mas tutoriales.

Copyright 2004 Red Hat Middleware, LLC.

Vous aimerez peut-être aussi