667 lines
31 KiB
XML
667 lines
31 KiB
XML
<chapter id="quickstart">
|
|
<title>Comienzo rápido con Tomcat</title>
|
|
|
|
<sect1 id="quickstart-intro" revision="2">
|
|
<title>Empezando con Hibernate</title>
|
|
|
|
<para>
|
|
Este tutorial explica una instalación de Hibernate con el
|
|
contenedor de servlets Apache Tomcat (hemos usado la versión 4.1,
|
|
las diferencias con la 5.0 deben ser mínimas) para una aplicación
|
|
basada en web. Hibernate trabaja bien en un entorno manejado con
|
|
todos los servidores de aplicaciones J2EE importantes, o incluso en aplicaciones
|
|
Java independientes. El sistema de base de datos es sólo una cuestión
|
|
de cambiar la configuración del dialecto SQL de Hibernate y las
|
|
propiedades de conexión.
|
|
</para>
|
|
|
|
<para>
|
|
Primero, tenemos que copiar todas las bibliotecas requeridas a la instalación
|
|
de Tomcat. Usamos un contexto web separado (<literal>webapps/quickstart</literal>)
|
|
para este tutorial, de modo que tenemos que considerar tanto la ruta de búsqueda
|
|
de bibliotecas global (<literal>TOMCAT/common/lib</literal>) como también
|
|
el cargador de clases a nivel de contexto en <literal>webapps/quickstart/WEB-INF/lib</literal>
|
|
(para ficheros JAR) y <literal>webapps/quickstart/WEB-INF/classes</literal>.
|
|
Nos referiremos a ambos niveles de cargador de clases como el classpath global y el classpath
|
|
de contexto, respectivamente.
|
|
</para>
|
|
|
|
<para>
|
|
Ahora, copia las bibliotecas a los dos classpaths:
|
|
</para>
|
|
|
|
<orderedlist>
|
|
<listitem>
|
|
<para>
|
|
Copia el driver JDBC para la base de datos al classpath global. Esto se
|
|
requiere para el software de pool de conexiones DBCP que se distribuye
|
|
con Tomcat. Hibernate usa conexiones JDBC para ejecutar SQL sobre la base de
|
|
datos, de modo que, o bien tienes que proveer conexiones JDBC en pool,
|
|
o bien configurar Hibernate para que use uno de los pools soportados
|
|
directamente (C3P0, Proxool). Para este tutorial, copia la biblioteca
|
|
<literal>pg74jdbc3.jar</literal> (para PostgreSQL 7.4 y JDK 1.4) al
|
|
classpath del cargador global. Si quisieras usar una base de datos diferente,
|
|
simplemente copia su apropiado driver JDBC.
|
|
</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
Nunca copies nada más dentro de la ruta del cargador de clases global
|
|
en Tomcat, o tendrás problemas con varias herramientas, incluyendo
|
|
Log4J, commons-logging y otras. Siempre usa el classpath de contexto para
|
|
cada aplicación web, esto es, copia las bibliotecas a
|
|
<literal>WEB-INF/lib</literal> y tus propias clases y ficheros de
|
|
configuración/propiedades a <literal>WEB-INF/classes</literal>.
|
|
Ambos directorios están a nivel del classpath de contexto por defecto.
|
|
</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
Hibernate está empaquetado como una biblioteca JAR. El fichero
|
|
<literal>hibernate3.jar</literal> debe ser copiado en el classpath de contexto
|
|
junto a las otras clases de la aplicación. Hibernate requiere algunas
|
|
bibliotecas de terceros en tiempo de ejecución; éstas vienen
|
|
incluídas con la distribución de Hibernate en el directorio
|
|
<literal>lib/</literal>. Ver <xref linkend="3rdpartylibs"/>. Copia las
|
|
bibliotecas de terceros requeridas al classpath de contexto.
|
|
</para>
|
|
</listitem>
|
|
</orderedlist>
|
|
|
|
<table frame="topbot" id="3rdpartylibs">
|
|
<title>
|
|
Bibliotecas de terceros de Hibernate
|
|
</title>
|
|
<tgroup cols="2" rowsep="1" colsep="1">
|
|
<colspec colname="c1" colwidth="1*"/>
|
|
<colspec colname="c2" colwidth="2*"/>
|
|
<thead>
|
|
<row>
|
|
<entry align="center">
|
|
Biblioteca
|
|
</entry>
|
|
<entry align="center">
|
|
Descripción
|
|
</entry>
|
|
</row>
|
|
</thead>
|
|
<tbody>
|
|
<row>
|
|
<entry>
|
|
antlr (requerida)
|
|
</entry>
|
|
<entry>
|
|
Hibernate usa ANTLR para producir analizadores de consultas,
|
|
esta biblioteca también se necesita en tiempo de ejecución.
|
|
</entry>
|
|
</row>
|
|
<row>
|
|
<entry>
|
|
dom4j (requerida)
|
|
</entry>
|
|
<entry>
|
|
Hibernate usa dom4j para analizar ficheros de configuración
|
|
XML y ficheros de metadatos de mapeo XML.
|
|
</entry>
|
|
</row>
|
|
<row>
|
|
<entry>
|
|
CGLIB, asm (requerida)
|
|
</entry>
|
|
<entry>
|
|
Hibernate usa la biblioteca de generación de código
|
|
para aumentar las clases en tiempo de ejecución
|
|
(en combinación con reflección Java).
|
|
</entry>
|
|
</row>
|
|
<row>
|
|
<entry>
|
|
Commons Collections, Commons Logging (requeridas)
|
|
</entry>
|
|
<entry>
|
|
Hibernate usa varias bibliotecas de utilidad del proyecto
|
|
Jakarta Commons de Apache.
|
|
</entry>
|
|
</row>
|
|
<row>
|
|
<entry>
|
|
EHCache (requerida)
|
|
</entry>
|
|
<entry>
|
|
Hibernate puede usar varios provedores de caché para
|
|
el caché de segundo nivel. EHCache es el provedor de
|
|
caché por defecto si no se cambia en la configuración.
|
|
</entry>
|
|
</row>
|
|
<row>
|
|
<entry>
|
|
Log4j (opcional)
|
|
</entry>
|
|
<entry>
|
|
Hibernate usa la API de Commons Logging, que a su vez puede
|
|
usar Log4J como el mecanismo de logging subyacente. Si la
|
|
biblioteca Log4J está disponible en el directorio de
|
|
bibliotecas del contexto, Commons Logging usará Log4J
|
|
y la configuración <literal>log4j.properties</literal>
|
|
en el classpath de contexto. Un fichero de propiedades de ejemplo
|
|
para Log4J se incluye con la distribución de Hibernate.
|
|
Así que copia log4j.jar y el fichero de configuración
|
|
(de <literal>src/</literal>) a tu classpath de contexto si quieres
|
|
ver que ocurre tras escénas.
|
|
</entry>
|
|
</row>
|
|
<row>
|
|
<entry>
|
|
¿Requerida o no?
|
|
</entry>
|
|
<entry>
|
|
Echa una mirada al fichero <literal>lib/README.txt</literal> en la
|
|
distribución de Hibernate. Esta es una lista actualizada
|
|
de bibliotecas de terceros distribuídas con Hibernate.
|
|
Encontrarás listadas ahí todas las bibliotecas
|
|
requeridas y opcionales (Observa que "buildtame required" significa
|
|
aquí para la construcción de Hibernate, no de tu
|
|
aplicación).
|
|
</entry>
|
|
</row>
|
|
</tbody>
|
|
</tgroup>
|
|
</table>
|
|
|
|
<para>
|
|
Ahora instalamos el pooling y modo compartido de conexiones de base de datos
|
|
tanto en Tomcat como Hibernate. Esto significa que Tomcat proveerá
|
|
conexiones JDBC en pool (usando su funcionalidad prefabricada de pooling DBCP).
|
|
Hibernate pide esas conexiones a través de JNDI. Alternativamente,
|
|
puedes dejar que Hibernate maneje el pool de conexiones. Tomcat liga su pool
|
|
de conexiones a JNDI; agregamos una declaración de recurso al fichero
|
|
de configuración principal de Tomcat, <literal>TOMCAT/conf/server.xml</literal>:
|
|
</para>
|
|
|
|
<programlisting><![CDATA[<Context path="/quickstart" docBase="quickstart">
|
|
<Resource name="jdbc/quickstart" scope="Shareable" type="javax.sql.DataSource"/>
|
|
<ResourceParams name="jdbc/quickstart">
|
|
<parameter>
|
|
<name>factory</name>
|
|
<value>org.apache.commons.dbcp.BasicDataSourceFactory</value>
|
|
</parameter>
|
|
|
|
<!-- DBCP database connection settings -->
|
|
<parameter>
|
|
<name>url</name>
|
|
<value>jdbc:postgresql://localhost/quickstart</value>
|
|
</parameter>
|
|
<parameter>
|
|
<name>driverClassName</name><value>org.postgresql.Driver</value>
|
|
</parameter>
|
|
<parameter>
|
|
<name>username</name>
|
|
<value>quickstart</value>
|
|
</parameter>
|
|
<parameter>
|
|
<name>password</name>
|
|
<value>secret</value>
|
|
</parameter>
|
|
|
|
<!-- DBCP connection pooling options -->
|
|
<parameter>
|
|
<name>maxWait</name>
|
|
<value>3000</value>
|
|
</parameter>
|
|
<parameter>
|
|
<name>maxIdle</name>
|
|
<value>100</value>
|
|
</parameter>
|
|
<parameter>
|
|
<name>maxActive</name>
|
|
<value>10</value>
|
|
</parameter>
|
|
</ResourceParams>
|
|
</Context>]]></programlisting>
|
|
|
|
<para>
|
|
El contexto que configuramos en este ejemplo se llama <literal>quickstart</literal>,
|
|
su base es el directorio <literal>TOMCAT/webapp/quickstart</literal>. Para acceder
|
|
a cualquier servlet, llama a la ruta <literal>http://localhost:8080/quickstart</literal>
|
|
en tu navegador (por supuesto, agregando el nombre del servlet como se mapee en tu
|
|
<literal>web.xml</literal>). Puedes también ir más allá y crear
|
|
ahora un servlet simple que tenga un método <literal>process()</literal>
|
|
vacío.
|
|
</para>
|
|
|
|
<para>
|
|
Tomcat provee ahora conexiones a través de JNDI en
|
|
<literal>java:comp/env/jdbc/quickstart</literal>. Si tienes problemas obteniendo
|
|
el pool de conexiones en ejecución, refiérete a la documentación
|
|
de Tomcat. Si obtienes mensajes de excepción del driver JDBC, intenta instalar
|
|
primero el pool de conexiones JDBC sin Hibernate. Hay disponibles en la Web
|
|
tutoriales de Tomcat y JDBC.
|
|
</para>
|
|
|
|
<para>
|
|
Tu próximo paso es configurar Hibernate. Hibernate tiene que saber cómo
|
|
debe obtener conexiones JDBC. Usamos la configuración de Hibernate basada en XML.
|
|
El otro enfoque, usando un ficheros de propiedad, es casi equivalente pero pierde unas
|
|
pocas funcionalidades que sí permite la sintaxis XML. El fichero de configuración
|
|
XML se ubica en el classpath de contexto (<literal>WEB-INF/classes</literal>), como
|
|
<literal>hibernate.cfg.xml</literal>:
|
|
</para>
|
|
|
|
<programlisting><![CDATA[<?xml version='1.0' encoding='utf-8'?>
|
|
<!DOCTYPE hibernate-configuration PUBLIC
|
|
"-//Hibernate/Hibernate Configuration DTD//EN"
|
|
"http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
|
|
|
|
<hibernate-configuration>
|
|
|
|
<session-factory>
|
|
|
|
<property name="connection.datasource">java:comp/env/jdbc/quickstart</property>
|
|
<property name="show_sql">false</property>
|
|
<property name="dialect">org.hibernate.dialect.PostgreSQLDialect</property>
|
|
|
|
<!-- Mapping files -->
|
|
<mapping resource="Cat.hbm.xml"/>
|
|
|
|
</session-factory>
|
|
|
|
</hibernate-configuration>]]></programlisting>
|
|
|
|
<para>
|
|
Desactivamos el registro (logging) de comandos SQL y decimos a Hibernate
|
|
qué dialecto SQL de base de datos se usa y dónde obtener
|
|
conexiones JDBC (declarando la dirección JNDI del pool ligado a
|
|
Tomcat). El dialecto es una configuración requerida, las bases de
|
|
datos difieren en su interpretación del "estándar" de SQL.
|
|
Hibernate cuidará de las diferencias y viene con dialectos incluídos
|
|
para todas las principales bases de datos comerciales y de código
|
|
abierto.
|
|
</para>
|
|
|
|
<para>
|
|
Una <literal>SessionFactory</literal> es el concepto de Hibernate
|
|
de un almacén de datos solo. Pueden usarse múltiples
|
|
bases de datos creando múltiples ficheros de configuración
|
|
XML y creando múltiples objetos <literal>Configuration</literal>
|
|
y <literal>SessionFactory</literal> en tu aplicación.
|
|
</para>
|
|
|
|
<para>
|
|
El último elemento del <literal>hibernate.cfg.xml</literal>
|
|
declara <literal>Cat.hbm.xml</literal> como el nombre de un fichero
|
|
de mapeo XML para la clase persistente <literal>Cat</literal>. Este
|
|
fichero contiene los metadatos para el mapeo de la clase POJO
|
|
<literal>Cat</literal> a una tabla (o tablas) de base de datos.
|
|
Volveremos a este fichero pronto. Escribamos primero la clase POJO
|
|
y luego declaremos los metadatos de mapeo para ella.
|
|
</para>
|
|
|
|
</sect1>
|
|
|
|
<sect1 id="quickstart-persistentclass" revision="1">
|
|
<title>Primera clase persistente</title>
|
|
|
|
<para>
|
|
Hibernate trabaja mejor con el modelo de programación de los
|
|
Viejos Objetos Planos de Java (POJOs, a veces llamados Ordinarios Objetos Planos de Java)
|
|
para clases persistentes. Un POJO es como un JavaBean, con las propiedades
|
|
de la clase accesible vía métodos getter y setter,
|
|
encapsulando la representación interna de la interfaz publicamente
|
|
visible (Hibernate puede también acceder a los campos directamente, si se
|
|
necesita):
|
|
</para>
|
|
|
|
<programlisting><![CDATA[package org.hibernate.examples.quickstart;
|
|
|
|
public class Cat {
|
|
|
|
private String id;
|
|
private String name;
|
|
private char sex;
|
|
private float weight;
|
|
|
|
public Cat() {
|
|
}
|
|
|
|
public String getId() {
|
|
return id;
|
|
}
|
|
|
|
private void setId(String id) {
|
|
this.id = id;
|
|
}
|
|
|
|
public String getName() {
|
|
return name;
|
|
}
|
|
|
|
public void setName(String name) {
|
|
this.name = name;
|
|
}
|
|
|
|
public char getSex() {
|
|
return sex;
|
|
}
|
|
|
|
public void setSex(char sex) {
|
|
this.sex = sex;
|
|
}
|
|
|
|
public float getWeight() {
|
|
return weight;
|
|
}
|
|
|
|
public void setWeight(float weight) {
|
|
this.weight = weight;
|
|
}
|
|
|
|
}]]></programlisting>
|
|
|
|
<para>
|
|
Hibernate no está restringido en su uso de tipos de propiedad, todos
|
|
los tipos y tipos primitivos del JDK de Java (como <literal>String</literal>,
|
|
<literal>char</literal> y <literal>Date</literal>) pueden ser mapeados, incluyendo
|
|
clases del framework de colecciones de Java. Puedes mapearlos como valores,
|
|
colecciones de valores, o asociaciones a otras entidades. El <literal>id</literal>
|
|
es una propiedad especial que representa el identificador de base de datos (clave
|
|
primaria) de la clase. Es altamente recomendado para entidades como un
|
|
<literal>Cat</literal>. Hibernate puede usar identificadores sólo
|
|
internamente, pero perderíamos algo de la flexibilidad en nuestra
|
|
arquitectura de aplicación.
|
|
</para>
|
|
|
|
<para>
|
|
No tiene que implementarse ninguna interface especial para las clases persistentes
|
|
ni tienes que subclasear de una clase persistente raíz en especial. Hibernate
|
|
tampoco requiere ningún procesamiento en tiempo de construcción,
|
|
como manipulación del byte-code. Se basa solamente en reflección de Java
|
|
y aumentación de clases en tiempo de ejecución (a través de CGLIB).
|
|
De modo que, sin ninguna dependencia de la clase POJO en Hibernate, podemos mapearla
|
|
a una tabla de base de datos.
|
|
</para>
|
|
|
|
</sect1>
|
|
|
|
<sect1 id="quickstart-mapping" revision="1">
|
|
<title>Mapeando el gato</title>
|
|
|
|
<para>
|
|
El fichero de mapeo <literal>Cat.hbm.xml</literal> contiene los
|
|
metadatos requeridos para el mapeo objeto/relacional. Los metadatos
|
|
incluyen la declaración de clases persistentes y el mapeo de
|
|
propiedades (a columnas y relaciones de claves foráneas a otras
|
|
entidades) a tablas de base de datos.
|
|
</para>
|
|
|
|
<programlisting><![CDATA[<?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>
|
|
|
|
<class name="org.hibernate.examples.quickstart.Cat" table="CAT">
|
|
|
|
<!-- A 32 hex character is our surrogate key. It's automatically
|
|
generated by Hibernate with the UUID pattern. -->
|
|
<id name="id" type="string" unsaved-value="null" >
|
|
<column name="CAT_ID" sql-type="char(32)" not-null="true"/>
|
|
<generator class="uuid.hex"/>
|
|
</id>
|
|
|
|
<!-- A cat has to have a name, but it shouldn' be too long. -->
|
|
<property name="name">
|
|
<column name="NAME" length="16" not-null="true"/>
|
|
</property>
|
|
|
|
<property name="sex"/>
|
|
|
|
<property name="weight"/>
|
|
|
|
</class>
|
|
|
|
</hibernate-mapping>]]></programlisting>
|
|
|
|
<para>
|
|
Cada clase persistente debe tener un atributo identificador (realmente,
|
|
sólo las clases que representen entidades, no las clases dependientes
|
|
de tipo-valor, que son mapeadas como componentes de una entidad). Esta propiedad
|
|
es usada para distinguir los objetos persistentes: Dos gatos son iguales si
|
|
<literal>catA.getId().equals(catB.getId())</literal> es verdadero. Este concepto
|
|
se llama <emphasis>identidad de base de datos (database identity)</emphasis>.
|
|
Hibernate viene empaquetado con varios generadores de identificador para diferentes
|
|
escenarios (incluyendo generadores nativos para secuencias de base de datos, tablas
|
|
de identificadores alto/bajo, e identificadores asignados por aplicación).
|
|
Usamos el generador UUID (recomendado sólo para pruebas, pues deben
|
|
preferirse las claves enteras delegadas generadas por la base de datos) y
|
|
también especificamos la columna <literal>CAT_ID</literal> de la tabla
|
|
<literal>CAT</literal> para el valor identificador generado por Hibernate
|
|
(como una clave primaria de la tabla).
|
|
</para>
|
|
|
|
<para>
|
|
Todas las demás propiedades de <literal>Cat</literal> son mapeadas a la
|
|
misma tabla. En el caso de la propiedad <literal>name</literal>, la hemos mapeado
|
|
con una declaración explícita de columna de base de datos. Esto es
|
|
especialmente útil cuando el esquema de base de datos es generado
|
|
automáticamente (como sentencias DDL de SQL) desde la declaración
|
|
de mapeo con la herramienta <emphasis>SchemaExport</emphasis> de Hibernate.
|
|
Todas las demás propiedades son mapeadas usando la configuración
|
|
por defecto de Hibernate, que es lo que necesitas la mayoría del tiempo.
|
|
La tabla <literal>CAT</literal> en la base de datos se ve así como:
|
|
</para>
|
|
|
|
<programlisting><![CDATA[ Columna | Tipo | Modificadores
|
|
--------+-----------------------+-----------
|
|
cat_id | character(32) | not null
|
|
name | character varying(16) | not null
|
|
sex | character(1) |
|
|
weight | real |
|
|
Indexes: cat_pkey primary key btree (cat_id)]]></programlisting>
|
|
|
|
<para>
|
|
Ahora debes crear esta tabla manualmente en tu base de datos, y luego leer el
|
|
<xref linkend="toolsetguide"/> si quieres automatizar este paso con la
|
|
herramienta <literal>hbm2ddl</literal>. Esta herramienta puede crear un
|
|
DDL SQL completo, incluyendo definición de tablas, restricciones
|
|
personalizadas de tipo de columnas, restricciones de unicidad e índices.
|
|
</para>
|
|
|
|
</sect1>
|
|
|
|
<sect1 id="quickstart-playingwithcats" revision="2">
|
|
<title>Jugando con gatos</title>
|
|
|
|
<para>
|
|
Ahora estamos listos para comenzar la <literal>Session</literal> de Hibernate.
|
|
Es el <emphasis>manejador de persistencia</emphasis> que usamos para almacenar
|
|
y traer <literal>Cat</literal>s hacia y desde la base de datos. Pero primero,
|
|
tenemos que obtener una <literal>Session</literal> (unidad de trabajo de Hibernate)
|
|
de la <literal>SessionFactory</literal>:
|
|
</para>
|
|
|
|
<programlisting><![CDATA[SessionFactory sessionFactory =
|
|
new Configuration().configure().buildSessionFactory();]]></programlisting>
|
|
|
|
<para>
|
|
La llamada a <literal>configure()</literal> carga el fichero de
|
|
configuración <literal>hibernate.cfg.xml</literal> e
|
|
inicializa la instancia de <literal>Configuration</literal>.
|
|
Puedes establecer otras propiedades (e incluso cambiar los metadatos de mapeo)
|
|
accediendo a la <literal>Configuration</literal> <emphasis>antes</emphasis>
|
|
que construyas la <literal>SessionFactory</literal> (que es inmutable).
|
|
¿Dónde creamos la <literal>SessionFactory</literal> y cómo
|
|
accedemos a ella en nuestra aplicación?
|
|
</para>
|
|
|
|
<para>
|
|
Una <literal>SessionFactory</literal> usualmente se construye una vez,
|
|
por ejemplo, al arrancar con un servlet <emphasis>load-on-startup</emphasis>.
|
|
Esto significa también que no debes mantenerla en una variable de instancia
|
|
en tus servlets, sino en alguna otro sitio. Además, necesitamos algún
|
|
tipo de <emphasis>Singleton</emphasis>, de modo que podamos acceder a la
|
|
<literal>SessionFactory</literal> fácilmente en el código de
|
|
aplicación. El siguiente enfoque mostrado resuelve ambos problemas:
|
|
configuración de arranque y fácil acceso a una
|
|
<literal>SessionFactory</literal>.
|
|
</para>
|
|
|
|
<para>
|
|
Implementamos una clase de ayuda <literal>HibernateUtil</literal>:
|
|
</para>
|
|
|
|
<programlisting><![CDATA[import org.hibernate.*;
|
|
import org.hibernate.cfg.*;
|
|
|
|
public class HibernateUtil {
|
|
|
|
private static Log log = LogFactory.getLog(HibernateUtil.class);
|
|
|
|
private static final SessionFactory sessionFactory;
|
|
|
|
static {
|
|
try {
|
|
// Create the SessionFactory
|
|
sessionFactory = new Configuration().configure().buildSessionFactory();
|
|
} catch (Throwable ex) {
|
|
// Make sure you log the exception, as it might be swallowed
|
|
log.error("Initial SessionFactory creation failed.", ex);
|
|
throw new ExceptionInInitializerError(ex);
|
|
}
|
|
}
|
|
|
|
public static final ThreadLocal session = new ThreadLocal();
|
|
|
|
public static Session currentSession() {
|
|
Session s = (Session) session.get();
|
|
// Open a new Session, if this Thread has none yet
|
|
if (s == null) {
|
|
s = sessionFactory.openSession();
|
|
session.set(s);
|
|
}
|
|
return s;
|
|
}
|
|
|
|
public static void closeSession() {
|
|
Session s = (Session) session.get();
|
|
if (s != null)
|
|
s.close();
|
|
session.set(null);
|
|
}
|
|
}]]></programlisting>
|
|
|
|
<para>
|
|
Esta clase no sólo cuida de la <literal>SessionFactory</literal>
|
|
con su inicializador static, sino que además tiene una variable
|
|
<literal>ThreadLocal</literal> que tiene la <literal>Session</literal>
|
|
para la hebra actual. Asegúrate de entender el concepto Java de una
|
|
variable local a una hebra antes de intentar usar esta ayuda. Una clase
|
|
<literal>HibernateUtil</literal> más compleja y potente puede
|
|
encontrarse en <literal>CaveatEmptor</literal>, http://caveatemptor.hibernate.org/
|
|
</para>
|
|
|
|
<para>
|
|
Una <literal>SessionFactory</literal> es segura entre hebras, muchas hebras pueden
|
|
acceder a ella concurrentemente y pedirle <literal>Session</literal>s. Una
|
|
<literal>Session</literal> no es un objeto seguro entre hebras que representa
|
|
una sola unidad-de-trabajo con la base de datos. Las <literal>Session</literal>s
|
|
se abren desde una <literal>SessionFactory</literal> y son cerradas cuando
|
|
todo el trabajo está completo. Un ejemplo en el método
|
|
<literal>process()</literal> de tu servlet podría parecerse a esto
|
|
(sin manejo de excepciones):
|
|
</para>
|
|
|
|
<programlisting><![CDATA[Session session = HibernateUtil.currentSession();
|
|
Transaction tx = session.beginTransaction();
|
|
|
|
Cat princess = new Cat();
|
|
princess.setName("Princess");
|
|
princess.setSex('F');
|
|
princess.setWeight(7.4f);
|
|
|
|
session.save(princess);
|
|
|
|
tx.commit();
|
|
HibernateUtil.closeSession();]]></programlisting>
|
|
|
|
<para>
|
|
En una <literal>Session</literal>, cada operación de base de datos
|
|
ocurre dentro de una transacción que aísla las operaciones
|
|
de base de datos (incluso operaciones de sólo lectura).
|
|
Usamos la API de <literal>Transaction</literal> de Hibernate para
|
|
abstraer de la estrategia de transacciones subyacente (en nuestro caso,
|
|
transacciones JDBC). Esto permite que nuestro código sea desplegado
|
|
con transacciones manejadas por contenedor (usando JTA) sin cambio alguno.
|
|
</para>
|
|
|
|
<para>
|
|
Observa que puedes llamar <literal>HibernateUtil.currentSession();</literal>
|
|
tantas veces como quieras, siempre obtendrás la <literal>Session</literal>
|
|
actual de esta hebra. Tienes que asegurarte que la <literal>Session</literal>
|
|
sea cerrada después que se complete tu unidad-de-trabajo, ya sea en
|
|
código de tu servlet o en un filtro de servlet antes que la respuesta HTTP
|
|
sea enviada. El bonito efecto colateral de la segunda opción es la
|
|
fácil inicialización perezosa: la <literal>Session</literal> todavía
|
|
está abierta cuando se dibuja la vista, de modo que Hibernate puede cargar
|
|
objetos no inicializados mientras navegas tu actual grafo de objetos.
|
|
</para>
|
|
|
|
<para>
|
|
Hibernate tiene varios métodos que pueden ser usados para traer
|
|
objetos desde la base de datos. La forma más flexible es usando
|
|
el Lenguaje de Consulta de Hibernate (Hibernate Query Language o HQL),
|
|
que es una extensión orientada a objetos de SQL fácil de
|
|
aprender:
|
|
</para>
|
|
|
|
<programlisting><![CDATA[Transaction tx = session.beginTransaction();
|
|
|
|
Query query = session.createQuery("select c from Cat as c where c.sex = :sex");
|
|
query.setCharacter("sex", 'F');
|
|
for (Iterator it = query.iterate(); it.hasNext();) {
|
|
Cat cat = (Cat) it.next();
|
|
out.println("Female Cat: " + cat.getName() );
|
|
}
|
|
|
|
tx.commit();]]></programlisting>
|
|
|
|
<para>
|
|
Hibernate también ofrece una API <emphasis>consulta por criterios</emphasis>
|
|
orientada a objetos que puede ser usada para formular consultas de tipo seguro.
|
|
Por supuesto, Hibernate usa <literal>PreparedStatement</literal>s y ligado de
|
|
parámetros para toda la comunicación SQL con la base de datos.
|
|
También puedes usar la funcionalidad de consulta SQL directa de Hibernate
|
|
u obtener una conexión plana de JDBC de una <literal>Session</literal>
|
|
en casos raros.
|
|
</para>
|
|
|
|
</sect1>
|
|
|
|
<sect1 id="quickstart-summary" revision="1">
|
|
<title>Finalmente</title>
|
|
|
|
<para>
|
|
Rasguñamos solamente la superficie de Hibernate en este pequeño
|
|
tutorial. Por favor, observa que no incluimos ningún código
|
|
específico de servlet en nuestros ejemplos. Tienes que crear un servlet
|
|
por tí mismo e insertar el código de Hibernate como lo veas
|
|
ubicado.
|
|
</para>
|
|
|
|
<para>
|
|
Ten en mente que Hibernate, como capa de acceso a datos, está firmemente
|
|
integrado dentro de tu aplicación. Usualmente, todas las otras capas dependen
|
|
del mecanismo de persistencia. Asegúrate de entender las implicaciones
|
|
de este diseño.
|
|
</para>
|
|
|
|
<para>
|
|
Para un ejemplo de aplicación más compleja, ver
|
|
http://caveatemptor.hibernate.org/ y echa una mirada a los
|
|
otros tutoriales con links en http://www.hibernate.org/Documentation
|
|
</para>
|
|
|
|
</sect1>
|
|
|
|
</chapter>
|