HIBERNATE - Persistencia

  • Upload
    helyi

  • View
    102

  • Download
    0

Embed Size (px)

Citation preview

  • HIBERNATE - Persistencia relacional para Java Idiomtico

    Documentacin de Referencia de Hibernate

    3.3.1

    Traductor: Gonzalo Daz

    Copyright 2004 Red Hat Middleware, LLC.

    Prefacio1. Introduccin a Hibernate

    1.1. Prefacio1.2. Parte 1 - La Primera Aplicacin Hibernate

    1.2.1. La primera clase1.2.2. El archivo de mapeo1.2.3. Configuracin de Hibernate1.2.4. Construyendo con Ant1.2.5. Comienzo y ayudantes1.2.6. Cargar y almacenar objetos

    1.3. Parte 2 - Mapear asociaciones1.3.1. Mapear la clase Person1.3.2. Una asociacin unidireccional basada en un Set1.3.3. Trabajar con la asociacin1.3.4. Coleccin de valores1.3.5. Asociaciones bidireccionales1.3.6. Trabajar con vnculos bidireccionales

    1.4. Parte 3 - La aplicacin de web "Event Manager"1.4.1. Escribir el servlet bsico1.4.2. Procesamiento y presentacin1.4.3. Despliegue (deploy) y test

    1.5. Sumario2. Arquitectura

    2.1. Generalidades2.2. Estados de una instancia2.3. Integracin con JMX2.4. Soporte de JCA2.5. Sesiones contextuales

    3. Configuracin3.1. Configuracin programtica3.2. Obtener una SessionFactory3.3. Conexiones JDBC3.4. Propiedades optativas de configuracin

    3.4.1. Dialectos de SQL3.4.2. Captura (fetching) por Outer Join3.4.3. Streams Binarios3.4.4. Cach de 2do nivel y cach de consultas3.4.5. Sustituciones en el lenguaje de consultas.3.4.6. Estadsticas de Hibernate

    3.5. Logueo (logging, bitcora)3.6. Implementando una NamingStrategy3.7. Archivo de configuracin XML3.8. Integracin con los Servidores de Aplicacin J2EE

    3.8.1. Configuracin de una estrategia transaccional3.8.2. SessionFactory ligada a JNDI3.8.3. Manejo del contexto actual de la sesin con JTA3.8.4. Despliegue de JMX

    4. Clases Persistentes4.1. Un simple ejemplo de POJO

    HIBERNATE - Persistencia Relacional para Java Idiomtico http://www.hibernar.org/documentacion_es/castellano.html

    1 de 198 17/02/2009 09:25 a.m.

  • 4.1.1. Implemente un constructor sin argumentos4.1.2. Porvea una propiedad identificadora (optativo)4.1.3. Prefiera clases que no sean finales (optativo)4.1.4. Declare mtodos de acceso y "mutadores" (accessors, mutators) para los campos persistentes.

    4.2. Implementar herencia4.3. Implementar equals() y hashCode()4.4. Modelos dinmicos4.5. T-uplizadores4.6. Extensiones

    5. Mapeo O/R bsico5.1. Declaracin del mapeo

    5.1.1. El Doctype o "tipo de documento XML"5.1.1.1. EntityResolver

    5.1.2. hibernate-mapping5.1.3. class5.1.4. id

    5.1.4.1. Generator5.1.4.2. El algoritmo hi/lo5.1.4.3. El argoritmo UUID5.1.4.4. Columnas de identidad y secuencias5.1.4.5. Identificadores asignados5.1.4.6. Claves primarias assignadas por triggers

    5.1.5. Generadores de identificador mejorados.5.1.6. Optimizacin de los generadores de identificador5.1.7. composite-id5.1.8. discriminator5.1.9. version (optativo)5.1.10. timestamp (optativo)5.1.11. property5.1.12. many-to-one5.1.13. one-to-one5.1.14. natural-id5.1.15. component, dynamic-component5.1.16. properties5.1.17. subclass5.1.18. joined-subclass5.1.19. union-subclass5.1.20. join5.1.21. key5.1.22. elementos column y formula5.1.23. import5.1.24. any

    5.2. Tipos de Hibernate5.2.1. Entidades y "value types"5.2.2. "Value types" bsicos5.2.3. "Value types" hechos a medida

    5.3. Mapear una misma clase ms de una vez5.4. Identificadores de SQL entrecomillados5.5. Alternativas de meta-datos

    5.5.1. Usar marcadores de XDoclet5.5.2. Usar anotaciones de JDK 5.0

    5.6. Propiedades generadas5.7. Objetos auxiliares de base de datos

    6. Mapeo de Colecciones6.1. Colecciones persistentes6.2. Mapeo de colecciones

    6.2.1. Claves forneas de las colecciones6.2.2. Elementos de la coleccin6.2.3. Colecciones indexadas6.2.4. Colecciones de valores y asociaciones de-muchos-a-muchos6.2.5. Asociaciones de-uno-a-muchos

    6.3. Mapeos de coleccin avanzados6.3.1. Colecciones ordenadas

    HIBERNATE - Persistencia Relacional para Java Idiomtico http://www.hibernar.org/documentacion_es/castellano.html

    2 de 198 17/02/2009 09:25 a.m.

  • 6.3.2. Asociaciones bidireccionales6.3.3. Asociaciones bidireccionales con colecciones indexadas6.3.4. Asociaciones ternarias6.3.5. Usar una

    6.4. Ejemplos de colecciones7. Mapeo de asociaciones

    7.1. Introduccin7.2. Asociaciones unidireccionales

    7.2.1. de-muchos-a-uno7.2.2. de-uno-a-uno7.2.3. de-uno-a-muchos

    7.3. Asociaciones unidireccionales con tablas de unin7.3.1. de-uno-a-muchos7.3.2. de-muchos-a-uno7.3.3. de-uno-a-uno7.3.4. de-muchos-a-muchos

    7.4. Asociaciones bidireccionales7.4.1. de-uno-a-muchos / de-muchos-a-uno7.4.2. de-uno-a-uno

    7.5. Asociaciones bidireccionales con tablas de unin7.5.1. de-uno-a-muchos / de-muchos-a-uno7.5.2. de-uno-a-uno7.5.3. de-muchos-a-muchos

    7.6. Mapeos de asociacoones ms complejas8. Mapeo de componentes

    8.1. Objetos dependientes8.2. Colecciones de objetos dependientes8.3. Comonentes usados como ndices de un Map8.4. Componentes usados como identificadores compuestos8.5. Componentes dinmicos

    9. Mapeo de herencia9.1. Las tres estrategias

    9.1.1. Una tabla por jerarqua de clases9.1.2. Una tabla por subclase9.1.3. Una tabla por subclase, usando un discriminador9.1.4. Mezclar "una tabla por jerarqua de clases" con "una tabla por subclase"9.1.5. Una tabla por cada clase concreta9.1.6. Una tabla por cada clase concreta, usando polimorfismo implcito9.1.7. Mezclar polimorfismo implcito con otras estrategias de mapeo de herencia

    9.2. Limitaciones10. Trabajar con objetos

    10.1. Estados de un objeto de Hibernate10.2. Hacer que los objetos se vuelvan persistentes10.3. Cargar un objeto10.4. Consultas

    10.4.1. Ejecutar consultas10.4.1.1. Iterar resultados10.4.1.2. Consultas que devuelven T-uplas10.4.1.3. Resultados escalares10.4.1.4. Parmetros vinculados10.4.1.5. Paginacin10.4.1.6. Iteracin navegable10.4.1.7. Externalizar consultas nombradas

    10.4.2. Filtrar colecciones10.4.3. Consultas "Criteria"10.4.4. Consultas en SQL nativo

    10.5. Modificar objetos persistentes10.6. Modificar objetos desprnendidos10.7. Deteccin automtica de estado10.8. Borrar objetos persistentes10.9. Replicar un objeto entre dos repositorios de datos distintos10.10. "Flush" de la sesin10.11. Persistencia transitiva

    HIBERNATE - Persistencia Relacional para Java Idiomtico http://www.hibernar.org/documentacion_es/castellano.html

    3 de 198 17/02/2009 09:25 a.m.

  • 10.12. Usar metadatos11. Transacciones y concurrencia

    11.1. La sesin y el alcance (scope) de las transacciones11.1.1. Unidad de trabajo11.1.2. Conversaciones largas11.1.3.Considerar la identidad de los objetos11.1.4. Problemas comunes

    11.2. Demarcacin de las transacciones de base de datos11.2.1. Entornos no administrados11.2.2. Usar JTA11.2.3. Manejo de excepciones11.2.4. Expiracin de transacciones

    11.3. Control optimista de concurrencia11.3.1. Chequeo de versin hecho por la aplicacin11.3.2. Sesin extendida y versionado automtico11.3.3. Objetos desprendidos y versionado automtico11.3.4. Crear un mtodo a medida para el versionado automtico

    11.4. "Lock" pesimista11.5. Modos de liberacin de conecciones

    12. Interceptores y eventos12.1. Interceptores12.2. Sistema de eventos12.3. Seguridad declarativa de Hibernate

    13. Procesamiento en lotes13.1. Inserciones en lotes13.2. Actualizaciones en lotes13.3. La interfaz StatelessSession13.4. Operaciones del tipo "Lenguaje de Modificacion de Datos" (DML-style)

    14. HQL: El lenguaje de consultas de Hibernate14.1. Relevancia de maysculas y minsculas14.2. La clusula "from"14.3. Asociaciones y "joins"14.4. Formas de la sintaxis de los "joins"14.5. Referirse a la propiedad identificadora14.6. La clusula "select"14.7. Funciones agregadas14.8. Consultas polimrficas14.9. La clusua "where"14.10. Expresiones14.11. La clusula "order by"14.12. La clusula "group by"14.13. Subconsultas14.14. Ejemplos de HQL14.15. Actualizaciones y borrados en masa14.16. Consejos y trucos14.17. Componentes14.18. Sintaxis del "Constructor de Valor de Fila" (row value constructor)

    15. Consultas "Criteria"15.1. Crear una instancia de Criteria15.2. Acotar el resultado15.3. Ordenar el resultado15.4. Asociaciones15.5. Captura dinmica de asociaciones15.6. Consultas "Example"15.7. Proyecciones, agregado y agrupamiento15.8. Consultas y subconsultas desprendidas15.9. Consultas por identificador natural

    16. SQL nativo16.1. Usar un SQLQuery

    16.1.1. Consultas escalares16.1.2. Consultas con entidades16.1.3. Manipular colecciones y asociaciones16.1.4. Devolver mltiples entidades

    HIBERNATE - Persistencia Relacional para Java Idiomtico http://www.hibernar.org/documentacion_es/castellano.html

    4 de 198 17/02/2009 09:25 a.m.

  • 16.1.4.1. Alias y referencias a propiedades16.1.5. Devolver entidades no administradas16.1.6. Manejar herencia16.1.7. Parmetros

    16.2. Consultas SQL nombradas16.2.1. Usar return-property para especificar nombres de columna/alias explcitamente16.2.2. Usar procedimientos almacenados (stored procedures) para efectuar consultas

    16.2.2.1. Reglas y limitaciones en el uso de procedimientos almacenados16.3. SQL a medida para crear, almacenar y borrar16.4. SQL a medida para cargar

    17. Filtrar datos17.1. Filtros de Hibernate

    18. Mapeo XML18.1. Trabajar con datos XML

    18.1.1. Especificar el mapeo XML y el mapeo de la clase al mismo tiempo18.1.2. Especificar slo un mapeo XML

    18.2. Metadatos del mapeo XML18.3. Manipulacin de los datos XML

    19. Mejorar la performance19.1. Estrategias de captura (fetch)

    19.1.1. Trabajar con asociaciones haraganas19.1.2. Ajustar las estrategias de captura19.1.3. Proxies de las asociaciones de un solo extremo19.1.4. Inicializar colecciones y proxies19.1.5. Usar la captura por lotes19.1.6. Usar la captura mediante subselects19.1.7. Usar la captura de propiedades haragana

    19.2. El cach de 2do nivel19.2.1. Mepeos de cach.19.2.2. Estrategia de slo lectura19.2.3. Estrategia de lecto/escritura19.2.4. Estrategia de lecto/escritura no estricta19.2.5. Estrategia transaccional19.2.6. Compatibilidad entre el proveedor de cach y la estrategia de concurrencia

    19.3. Admninistrar los cachs19.4. El cach de consultas (query cache)19.5. Comprender la performance de las colecciones

    19.5.1. Taxonoma19.5.2. Las lists, maps, idbags y sets son las colecciones ms eficientes de actualizar19.5.3. Las bags y lists son las colecciones inversas ms eficientes19.5.4. Borrado en una pasada

    19.6. Monitorear la performance19.6.1. Monitorear una SessionFactory19.6.2. Mediciones

    20. Gua de las herramientas (Toolset)20.1. Generacin automtica del esquema de base de datos

    20.1.1. Retocar el esquema de base de datos20.1.2. Ejecutar la herramienta20.1.3. Propiedades20.1.4. Usar Ant20.1.5. Actualizaciones incrementales del esquema de base de datos20.1.6. Utilizar Ant para las actualizaciones incrementales del esquema de base de datos20.1.7. Validacin del esquema de base de datos20.1.8. Usar Ant para la validacin del esquema de base de datos

    21. Ejemplo: Padre/Hijo21.1. Nota sobre las colecciones21.2. de-uno-a-muchos bidireccional21.3. Ciclo de vida de las propagaciones en cascada21.4. Propagaciones en cascada y unsaved-value21.5. Conclusin

    22. Ejemplo: La aplicacin Weblog22.1. Clases persistentes22.2. Mapeos de Hibernate

    HIBERNATE - Persistencia Relacional para Java Idiomtico http://www.hibernar.org/documentacion_es/castellano.html

    5 de 198 17/02/2009 09:25 a.m.

  • 22.3. Cdigo Hibernate23. Ejemplo: Mapeos varios

    23.1. Empleador/Empleado23.2. Autor/Obra23.3. Cliente/Orden/Producto23.4. Ejemplos miscelneos de asociacin

    23.4.1. Asociacin de-uno-a-uno "con tipo"23.4.2. Ejemplo de clave compuesta23.4.3. de-muchos-a-muchos con atributo compartido de clave compuesta23.4.4. Discriminacin basada en el contenido23.4.5. Asociaciones en claves alternativas

    24. Prcticas recomendadas

    Prefacio

    Trabajar con software orientado a objetos y bases de datos relacionales, puede ser embarazoso y demandar mucho tiempo,en los entornos corporativos actuales. Hibernate es una herramienta de mapeo objeto/relacional para ambientes Java. Eltrmino "mapeo objeto/relacional" (ORM por sus siglas en ingls) se refiere a esta tcnica de "mapear" la representacinde los datos desde un modelo de objetos hacia un modelo de datos relacional, con un esquema de base de datos basado enSQL.

    Hibernate no slo se hace cargo del mapeo de clases Java a las tablas de una base de datos (y de los tipos Java a los tiposde la base de datos), sino que tambin provee utilidades para consulta y captura de datos, y puede reducirconsiderablemente el tiempo que, de otra manera, habra que invertir con el manejo manual de datos mediante SQL yJDBC.

    La meta de Hibernate es aliviar al programador del 95% de las tareas ms comunes relacionadas con persistencia.Probablemente, Hibernate no sea la mejor solucin para aplicaciones data-cntricas que tengan casi toda su lgica denegocios en procedimientos almacenados (stored procedures) en la base de datos; es ms til con modelos orientados aobjetos cuya lgica de negocio reside en la capa intermedia. Sin embargo, Hibernate puede ayudarlo a encapsular oeliminar cdigo SQL que sea especfico de un proveedor de BD, y ayudar en la tarea usual de traducir desde unarepresentacin tabular a un grfico de objetos.

    Si usted es nuevo en Hibernate y en lo que respecta al Mapeo objeto/relacional, o incluso nuevo en Java, por favor siga lossiguientes pasos:

    Lea el siguiente instructivo: Captulo 1, Introduccin a Hibernate, el cual es una especie de manual coninstrucciones paso a paso. El cdigo fuente del instructivo est incluido en la distribucin descargable, en eldirectorio doc/reference/tutorial/

    Lea Captulo 2, Arquitectura para entender en qu entornos Hibernate puede ser usado.

    chele un vistazo al directorio eg/ en la distribucin de Hibernate. Contiene una simple aplicacin autosuficiente.Copie su driver de JDBC al directorio lib/ y edite etc/hibernate.properties, especificando valores correctospara su base de datos. Desde la consola, situado en el directorio de distribucin, tipee ant eg (usando Ant), o desdeWindows, tipee build eg.

    Use esta documentacin de referencia como su fuente primaria de informacin. Considere leer Java Persistencewith Hibernate (http://www.manning.com/bauer2) si necesita ms ayuda con el diseo de aplicaciones o si prefiereun instructivo paso a paso. Tambin visite http://caveatemptor.hibernate.org y descargue la aplicacin de ejemplopara Persistencia de Java con Hibernate.

    Las preguntas frecuentes (FAQ, por sus siglas en ingls), son contestadas en el sitio de web de Hibernate.

    En el sitio de web de Hibernate hay vnculos a demostraciones de terceros, ejemplos e instructivos.

    El rea Comunitaria del sitio de web de Hibernate es un buen recurso acerca de patrones de diseo y variassoluciones de integracin (Tomcat, JBoss AS, Struts, EJB, etc).

    Si tiene preguntas, utilice el foro en el sitio de Hibernate. Tambin proveemos un sistema JIRA de seguimiento deproblemas, para reportes de defectos (bugs) y pedidos de mejoras. Si a usted le interesa la programacin de Hibernate,nase a la lista de correo de programacin de Hibernate. Si le interesa traducir este documento, pngase en contacto connosotros en la lista de correo de programacin.

    HIBERNATE - Persistencia Relacional para Java Idiomtico http://www.hibernar.org/documentacion_es/castellano.html

    6 de 198 17/02/2009 09:25 a.m.

  • A travs de JBoss Inc, hay disponible soporte para desarrollo comercial y de produccin, y entrenamiento para Hibernate.(vase http://www.hibernate.org/SupportTraining/). Hibernate es un componente vital del paquete de productos conocidocomo "Sistema Empresarial JBoss de Middleware" (JEMS, por sus siglas en ingls).

    Captulo 1. Introduccin a Hibernate

    1.1. Prefacio

    Este captulo es una introduccin a Hibernate, con el tono de un instructivo, destinado a usuarios nuevos de Hibernate.Empezamos con una simple aplicacin que usa una base de datos residente en memoria. Construimos la aplicacin de apasos pequeos, fciles de comprender. Este instructivo se basa en otro anterior, escrito por Michael Gloegl. Todo elcdigo est contenido en el directorio tutorials/web del cdigo fuente del proyecto.

    Importante

    Este instructivo sobreentiende que el usuario ya tiene conocimiento de Java y de SQL. Si cualquiera deambos es nuevo para usted, o no se maneja bien ellos, le recomendamos que comience con una buenaintroduccin a estas tecnologas, antes de adentrarse en Hibernate. A la larga, le ahorrar tiempo yesfuerzo.

    Nota

    Hay otra aplicacin a modo de ejemplo/instructivo en el directorio del cdigo fuente /tutorials/eg.Dicho ejemplo se basa en lnea de comandos (consola), y como tal no depende de un contenedor de servletspara poder ser ejecutado. El montaje (setup) bsico es el mismo que para las instrucciones a continuacin.

    1.2. Parte 1 - La primera aplicacin Hibernate

    Supongamos que tenemos una pequea aplicacin de base de datos que puede almacenar eventos a los que queremosasistir, e informacin acerca del anfitrin (o anfitriones) de dichos eventos. Vamos a usar una base de datos residente enmemoria, llamada HSQLDB, para evitar describir la instalacin y configuracin de cualquier base de datos en particular.Sintase en libertad de usar cualquier base de datos con la que est familiarizado.

    Lo primero que tenemos que hacer es montar nuestro entorno de desarrollo, y, especficamente, instalar todas lasdependencias que Hibernate necesita, as como otras bibliotecas (libraries). Hibernate se construye usando Maven, el cual,entre otras cosas, provee manejo de dependencias. Ms an: provee un manejo transitivo de dependencias, lo cualsimplemente significa que para usar Hibernate podemos definir nuestras dependencias dentro de l: Hibernate mismodefine las dependencias que necesita, las cuales se convierten en "transitivas".

    .

  • Nota

    Bsicamente, aqu estamos describiendo el archivo /tutorials/web/pom.xml. Vea el sitio de Maven params informacin.

    Consejo

    Aunque no es estrictamente necesario, muchos entornos visuales de progrmacin (IDEs) ya cuentan conintegracin con Maven para leer estos archivos POM, y automticamente generar el proyecto por usted (locual puede ahorrar mucho tiempo y esfuerzo).

    Luego creamos una clase que representa el evento que queremos almacenar en la base de datos.

    1.2.1. La primera clase

    Nuestra primera clase persistente es un simple 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; }}

    Se puede ver que esta clase usa la convencin estndar de JavBeans para nombrar a sus mtodos "setter" y "getter"(escritura y lectura de propiedades, respectivamente). Este diseo es el recomendado - pero no es obligatorio. Hibernatepuede aceder a los campos directamente; la ventaja de los mtodos de acceso es proveer mayor solidez a la hora de refinar("refactoring") el cdigo. El constructor sin argumentos s es obligatorio, para poder instanciar el objeto mediantereflexin.

    La propiedad identificadora o id contiene un identificador nico para un evento en particular. Todas las clases de entidadpersistentes (las hay menos importantes tambin) necesitarn dicho id, si queremos usar a pleno las capacides deHibernate. De hecho, la mayora de las aplicaciones (especialmente aplicaciones de web), ya necesitan distinguir objetospor id, as que esta caracterstica debera considerarse una ventaja, ms que una limitacin. De todos modos, usualmenteno manipulamos directamente la identidad de un objeto, as que el mtodo "setter" del id debera ser privado. SloHibernate asigna ids, cuando el objeto es grabado. Hibernate puede acceder a mtodos en cualquier nivel de acceso(protected, public, private, etc) directamente. La opcin de qu nivel de acceso utilizar es suya, segn el diseo de suaplicacin.

    HIBERNATE - Persistencia Relacional para Java Idiomtico http://www.hibernar.org/documentacion_es/castellano.html

    8 de 198 17/02/2009 09:25 a.m.

  • El constructor sin argumentos es obligatorio para todas las clases persistentes; Hibernate tiene que crear los objetos parausted utilizando Java Reflection. El constructor puede ser privado; sin embargo, para poder generar "proxies" en tiempo deejecucin, y para la captura de datos sin la construccin de bytecode, se requiere al menos el nivel de acceso "package" opor defecto.

    Ponga este archivo de cdigo fuente Java en un directorio llamado src en el directorio de desarrollo, y dentro del paquetecorrespondiente. El directorio debera verse as:

    .+lib +src +events Event.java

    En el paso siguiente, le vamos a informar a Hibernate acerca de esta clase persistente.

    1.2.2. El archivo de mapeo

    Hibernate necesita saber cmo cargar y almacenar objetos de la clase persistente. Aqu es donde entra en juego el archivode mapeo. ste le dice a Hibernate a qu tabla en qu base de datos tiene que acceder, y qu columnas de dicha tablatiene que utilizar.

    La estructura bsica del archivo de mapeo se ve as:

    [...]

    Ntese que la DTD de Hibernate es bastante sofisticada. La puede usar para autocompletar elementos de mapeo yatributos de XML en su indetfaz grfica (IDE). Tambin puede abrir la el archivo de la DTD en su procesador de texto - esla forma ms fcil de tener una visin general de todos los elementos, y de ver los valores por defecto, junto con algunoscomentatios. Sepa que Hibernate no buscar la DTD en la red, sino en el classpath. La DTD est incluida en el archivo,hibernate3.jar, as como en el directorio src/ de la distribucin de Hibernate.

    En los ejemplos sucesivos, omitiremos la declaracin de la DTD, por brevedad. Por supuesto, sta no es optativa.

    Entre las dos tags hibernate-mapping, incluya un elemento class. Todas las clases de entidad persistente (de nuevo: hayclases dependientes, como veremos luego, que no son entidades de primer nivel) necesitan dicho mapeo, a una tabla en labase de datos SQL.

    Hasta el momento, le hemos dicho a Hibernate cmo persistir y cargar un objeto de la clase Event en la tabla EVENTS,cada instancia representando un registro de la tabla. Ahora continuamos con el mapeo del identificador nico a la claveprimaria de la tabla. Por aadidura, como no queremos preocuparnos por manipular dicho identificador, configuramos una"estrategia de generacin de identificador" de Hibernate para que use una clave primaria "sustituta" (surrogate key).

    HIBERNATE - Persistencia Relacional para Java Idiomtico http://www.hibernar.org/documentacion_es/castellano.html

    9 de 198 17/02/2009 09:25 a.m.

  • El elemento id es la declaracuin de la propiedad indentificadora. El atributo name="id" declara el nombre de lapropiedad Java - Hibernate usar los mtodos getter y setter para acceder a ella. El atributo "column" le dice a Hibernatequ columna de la tabla EVENTS usamos como clave primaria. El elemento anidado generator especifica la estrategia parala generacin de identificador. En este caso, usamos native, la cual elige la mejor estrategia dependiendo de la BD ydialecto configurados. Hibernate soporta tanto identificadores generados por la base de datos, como globalmente nicos, oasignados por la aplicacin (o generados por cualquier estrategia para la cual usted haya escrito una extensin).

    Finalmente, incluimos declaraciones para las propiedades persistentes en el archivo de mapeo. Por defecto, ninguna de laspropiedades de la clase se considera persistente.

    Igual que con el elemento id, el atributo name del elemento property le dice a Hibernate qu mtodos getter y setter usar.As que, en este caso, Hibernate buscar getDate()/setDate(), as como getTitle()/setTitle().

    Por qu el mapeo de la propiedad date incluye el atributo column, pero el title no? A falta del atributo column,Hibernate por defecto usa el nombre de la propiedad como nombre de columna. Esto funciona para title. Pero date esuna palabra reservada en la mayora de las base de datoss, as que mejor la mapeamos con un nombre diferente.

    Otra cosa interesante, es que el mapeo title tambin carece del atributo type. Los tipos que usamos en los archivos demapeo no son, como es de esperarse, tipos Java. Tampoco son tipos SQL. A estos tipos se los llama Tipos de mapeo deHibernate, conversores que podemos traducir de tipos Java a SQL y viceversa. De nuevo, Hibernate tratar de determinarla conversin adecuada e incluso el tipo mismo, si el atributo type no se especifica en el mapeo. En algunos casos, estadeteccin automtica (que usa Java Reflection) puede no generar el valor por defecto que usted esperaba o necesita. sees el caso con la propiedad date. Hibernate no puede saber si la propiedad, que es del tipo java.util.Date, debera sermapeada a una columna timestamp, o a una columna time. En este caso, mantengamos la informacin completa (de da yhora) mapeando la propiedad al conversor timestamp.

    Este achivo de mapeo debera ser grabado como Event.hbm.xml, justo en el mismo directorio que el archivo Java de laclase Event. El nombre de los archivos de mapeo puede ser arbitrario, pero los sufijos hbm.xml son una convencin en lacomunidad de programadores de Hibernate. Ahora la estructura de directorios debera verse as:

    .+lib +src +events Event.java Event.hbm.xml

    Continuamos con la configuracin principal de Hibernate

    1.2.3. Configuracin de Hibernate

    Ahora tenemos ubicados una clase persistente y su archivo de mapeo. Es el momento de configurar Hibernate mismo.Antes de hacerlo, necesitamos una base de datos. HSQLBD es una base de datos basada en Java; puede ser descargada delsitio de web de HSQL DB (http://hsqldb.org/). En ralidad, usted slo necesita hsqldb.jar de dicha descarga. Coloqueeste archivo en el directorio lib/ del directorio de desarrollo.

    Cree un directorio llamado data en la raz del directorio de desarrollo - es ah en donde HSQL DB almacenar susarchivos de datos. Ahora, haga arrancar la base de datos ejecutando: java -classpath ../lib/hsqldb.jarorg.hsqldb.Server en este directorio de datos. Usted podr ver que arranca y est ligada a un socket TPC/IP. Ah esdonde nuestra aplicacn se conectar luego. Si quiere comenzar con una base de datos nueva en el transcurso de esteinstructivo, cierre la base de datos HSQL DB pulsando CTRL + C en la ventana, borre todos los archivos en el

    HIBERNATE - Persistencia Relacional para Java Idiomtico http://www.hibernar.org/documentacion_es/castellano.html

    10 de 198 17/02/2009 09:25 a.m.

  • subdirectorio data/, y arranque HSQL DB nuevamente.

    Hibernate es la capa de su aplicacin que se conecta con esta base de datos, as que necesita informacin de conexin. Lasconexiones se hacen mediante un pool de conexiones JDBC, el cual tambin tenemos que configurar. La distribucin deHibernate contiene varias herramientas de cdigo abierto (open source) que generan pool de conexiones , pero para esteinstructivo usaremos el pool que ya viene incorporado en Hibernate. Dse cuenta de que, si quiere usar un pool deconexiones JDBC de mayor calidad (para aplicaciones ya instaladas en produccin) hecho por terceros, deber copiar lasbibliotecas que hagan falta en el classpath, y usar propiedades de conexin diferentes.

    Para la configuracin de Hibernate, podemos usar un simple archvo hibernate.properties, un archivohibernate.cfg.xml un tanto ms sofisticado, o incluso una configuracin totalmente programtica. La mayora prefierael archivo de configuracin XML.

    org.hsqldb.jdbcDriver

    jdbc:hsqldb:hsql://localhost sa

    1

    org.hibernate.dialect.HSQLDialect

    thread

    org.hibernate.cache.NoCacheProvider

    true

    create

    Fjese en que este archivo de configuracin XML usa una DTD distinta. Configuramos la SessionFactory de Hibernate -una fabrica global responsable de una base de datos en particular. Si tiene varias base de datos, use varias configuracionesde por lo comn en otros tantos archivos de configuracin (para un arranque ms fcil).

    Los primeros 4 elementos property contienen la configuracin necesaria para la conexn JDBC. La propiedad "dialect"especifica la variante de SQL en particular que Hibernate genera. El manejo automtico de sesiones por contextos depersistencia ser muy til, como pronto veremos. La opcin hbm2ddl.auto activa la generacin automtica de esquemas -directamente en la BD. Esto por supuesto puede ser desactivado (quitando esta opcin) o ser redirigido a un archivo, conla ayuda de la tarea de Ant SchemaExport. Fnalmente, agregamos el o los archivo de mapeo para las clases persistentes ala configuracin.

    Copie este archivo en el directorio de fuentes (src), de manera que quede en la raz del classpath. Hibernate buscaautomticamente un arhivo llamado hibernate.cfg.xml en la raz del classpath, al arrancar.

    1.2.4. Construir con Ant

    HIBERNATE - Persistencia Relacional para Java Idiomtico http://www.hibernar.org/documentacion_es/castellano.html

    11 de 198 17/02/2009 09:25 a.m.

  • Ahora vamos a construir (build) esta aplicacin instructiva usando Ant. Deber tener Ant ya instalado - obtngalo de laPgina de descarga de Ant. Aqu no vamos a discutir cmo instalar Ant. Por favor refirase al Manual de Ant. Despus dehaber instalado Ant, podemos crear el archivo de construccin de Ant (build file), que se llamar build.xml, y estarsituado directamente en el directorio de desarrollo.

    Un archivo de construccin Ant bsico se ve as:

    Esto le dice a Ant que agregue todos los archivos del el directorio lib que terminen en .jar al classpath que usemos para lacompilacin. Tambin copiar todos los archivos fuente no-Java al directorio de destino (target), por ejemplo, los archivosde configuracin y mapeo.. Si ejecuta Ant ahora, debera obtener la siguiente salida:

    C:\hibernateTutorial\>antBuildfile: build.xml

    copy-resources: [copy] Copying 2 files to C:\hibernateTutorial\bin

    compile: [javac] Compiling 1 source file to C:\hibernateTutorial\bin

    BUILD SUCCESSFULTotal time: 1 second

    1.2.5. Arranque y ayudantes

    Es hora de cargar y grabar algunos objetos Event,pero primero debemos completar la instalacin (setup) con algo decdigo "infraestructural". Tenemos que hacer arrancar Hibernate. Dicho arranque incluye construir un objetoSessionFactory global, y almacenarlo en algn lugar de fcil acceso para el cdigo de la aplicacin. UnaSessionFactory puede abrir nuevos objetos Session. Cada objeto Session representa una "unidad de trabajo" de unsolo Thread. El cdigo de SessionFactory es thread-safe, y es instanciado slo una vez.

    Vamos a crear una clase de ayuda llamada HibernateUtil, que se encargar del arranque y har que el acceso aSessionFactory sea ms conveniente. Veamos cmo implementarla:

    package util;

    import org.hibernate.*;

    HIBERNATE - Persistencia Relacional para Java Idiomtico http://www.hibernar.org/documentacion_es/castellano.html

    12 de 198 17/02/2009 09:25 a.m.

  • import org.hibernate.cfg.*;

    public class HibernateUtil {

    private static final SessionFactory sessionFactory;

    static { try { // Cree la SessionFactory para hibernate.cfg.xml sessionFactory = new Configuration().configure().buildSessionFactory(); } catch (Throwable ex) { // Asegrese de loguear la excepcin, dado que puede ser "tragada" System.err.println("Initial SessionFactory creation failed." + ex); throw new ExceptionInInitializerError(ex); } }

    public static SessionFactory getSessionFactory() { return sessionFactory; }

    }

    Esta clase no slo produce la SessionFactory global, en un inicializador esttico (invocado una sola vez por la JVMcuando la clase se carga), sino que oculta el hecho de que se emplea un singleton esttico. Podra haber estado buscando laSessionFactory en el JNDI de un servidor de aplicaciones, , por ejemplo,.

    Si usted le da un nombre a la SessionFactory en su archivo de configuracin, Hibernate en realidad intentar vincularla aJNDI tras haber sido creada. Para omitir este cdigo completamente, usted tambin podra usar "despliegue JMX" y dejarque el un contenedor habilitado para JMX instancie y construya un HibernateService en la JNDI. Estas opcionesavanzadas se discuten en la documentacin de referencia de Hibernate.

    Coloque HibernateUtil.java en el directorio de cdigo fuente, en un paquete al lado de events:

    .+lib

    +src +events Event.java Event.hbm.xml +util HibernateUtil.java hibernate.cfg.xml+databuild.xml

    Esto debera poder compilarse sin problemas. Finalmente, necesitamos configurar un sistema de logueo (bitcora, logging)- Hibernate usa commons logging y le deja a usted la opcin entre log4j y el logging especfico de Java. La mayora de losprogramadores prefiere Log4j. Copie log4j.properties de la distribucin de Hibernate (est en el directorio etc/) a sudirectorio src, al lado de hibernate.cfg.xml. Dele un vistazo a la configuracin de ejemplo, y cambie los valores sidesea una salida ms locuaz. Por defecto, slo los mensajes de arranque de Hibernate se muestran en la salida estndar.

    La parte infraestructural del instructivo ha finalizado. Ahora estamos listos para efectuar verdadero trabajo con Hibernate.

    1.2.6. Cargar y almacenar objetos

    Finalmente podemos usar Hibernate para cargar y grabar objetos . Escribimos una clase EventManager con un mtodomain().

    package events;import org.hibernate.Session;

    import java.util.Date;

    import util.HibernateUtil;

    public class EventManager {

    public static void main(String[] args) {

    HIBERNATE - Persistencia Relacional para Java Idiomtico http://www.hibernar.org/documentacion_es/castellano.html

    13 de 198 17/02/2009 09:25 a.m.

  • 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(); }

    }

    Creamos un objeto Event, y se los pasamos a Hibernate. Ahora Hibernate se encarga del SQL, y ejecuta INSERTs en labase de datos. Echmosle un vistazo a la sesin, y al cdigo de manejo de transacciones antes de ejecutarlo.

    Usa sesin (Session) es una unidad de trabajo. Por ahora mantendremos todo simple y asumiremos una correspondenciauno-a-uno entre una sesin de Hibernate y una transaccin de BD. Para "escudar" nuestro codigo respecto del sistemasubyacente de transacciones (en este caso, slo JDBC, pero podra haber sido JTA), usamos la API para transacciones queest disponible en la clase Session.

    Qu hace sessionFactory.getCurrentSession()? Primero, a este mtodo se lo puede llamar desde dondequiera, ycuantas veces se desee, una vez que obtenemos una SessionFactory. (fcilmente, gracias a la HibernateUtil). El cdigogetCurrentSession() siempre devuelve la unidad "actual" de trabajo. Recuerda que configuramos una opcin convalor "thread" en hibernate.cfg.xml? Debido a esto, la unidad actual de trabajo est ligada al thread de Java que se estejecutando en ese momento en su aplicacin. De todos modos, sta no es toda la historia: tambin hay que considerar elalcance (scope), cundo una unidad de trabajo empieza y cundo termina.

    Una sesin comienza cuando se la necesita por primera vez, cuando se hace la primera llamada a getCurrentSession().Entonces, es ligada al thread actual por Hibernate. Cuando la transaccin termina, Hibernate desliga la sesin del thread, yla cierra por usted. Si usted llama getCurrentSession() de nuevo, obtiene una nueva sesin y comienza una nuevaunidad de trabajo. El modo de programacin "ligado a threads" (thread-bound), es la forma ms difundida de usarHibernate, dado que permite una distribucin en capas muy flexible: el cdigo de delimitacin de transacciones puedesepararse del cdigo de acceso a datos, como veremos ms adelante.

    En relacin al alcance de la unidad de trabajo: Una sesin debera usarse para ejecutar una sola operacin de base dedatos, o varias? El ejemplo precedente usa una sesin para una operacin. Esto es simple casualidad, el ejemplo no es losuficientemente complejo como para demostrar ningn otro enfoque. El alcance de una sesin de Hibernate es flexible,pero nunca se debe designar una aplicacin de maneera que utilice una sesin para cada operacin de base de datos. Asque, incluso si usted lo ve en algunos pocos de los ejemplos siguientes, considere la prctica de "una sesin por operacin"como algo a evitar (un "anti-pattern"). Una aplicacin real (de web) se analiza ms adelante en este instructivo.

    chele un vistazo al captulo Captulo 11, Transacciones y Concurrencia acerca del manejo de transacciones y sudelimitacin. Tambin hemos salteado cualquier manejo de errores en el ejemplo precedente.

    Para ejecutar esta primera rutina, tenemos que agregar una "target" invocable al archivo de construccin de Ant.

    El valor del argumento "action" se asigna en la lnea de comandos cuando esta target se invoca.

    HIBERNATE - Persistencia Relacional para Java Idiomtico http://www.hibernar.org/documentacion_es/castellano.html

    14 de 198 17/02/2009 09:25 a.m.

  • C:\hibernateTutorial\>ant run -Daction=store

    Despus de la compilacin, usted debera ver que que Hibernate arracna, y, dependiendo de su configuracin, un montnde salida de logueo. Al final encontrar la siguiente lnea:

    [java] Hibernate: insert into EVENTS (EVENT_DATE, title, EVENT_ID) values (?, ?, ?)

    se es el cdigo INSERT ejecutado por Hibernate. Los signos de interrogacin representan parmetros JDBC ligados. Paraver los valores de dichos parmetros, o para reducir la locuacidad del archivo de log, revise su archivolog4j.properties.

    Ahora, querramos tanbin listar los eventos almacenados, as que agregamos una opcin el el mtodo principal:

    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()); }}

    Tambin agregamos un nuevo mtodo listEvents() method:

    private List listEvents() {

    Session session = HibernateUtil.getSessionFactory().getCurrentSession();

    session.beginTransaction();

    List result = session.createQuery("from Event").list();

    session.getTransaction().commit();

    return result;}

    Lo que hicimos aqu, es usar el lenguaje de consultas de Hibernate (HQL, por sus siglas en ingls) para cargar todos losobjetos Event que existen en la base de datos. Hibernate generar el cdigo SQL que haga falta, lo enviar la base dedatos, y poblar los objetos Event con los datos que sean devueltos. Se pueden crear consultas SQL mucho ms complejascon HQL, por supuesto.

    Ahora, para ejecutar y chequear todo esto, siga estos pasos:

    Ejecute ant run -Daction=store para almacenar algo en la base de datos y, por supuesto, para previamentegenerar el esquema de base de datos mediante hbm2ddl.

    Ahora inhabilite hbm2ddl (convirtiendo la propiedad en un comentario) en el archivo hibernate.cfg.xml. Por logeneral, slo se la deja habilitada cuando se efecta un "unit testing continuo", pero en este caso, dejarla habilitadaborrara todo lo que usted haya almacenado hasta ese momento. (el valor de hbm2ddl="create" se traduce como"haga un DROP de todas las tablas del esquema, y recree todas las tablas cuando la SessionFactory sea construida")

    Si usted ahora invocara Ant con -Daction=list, debera ver los eventos que haya almacenado hasta ese moento. Porsupuesto, puede tambin invocar la accin store un par de veces ms.

    Nota: A esta altura, la mayora de los usuarios de Hibernate experimenta problemas, y aparecen seguido mensajes del tipoTable not found . De todos modos, si usted sigue los pasos que acabamos de describir cuidadosamente, no tendr esteproblema, ya que hbm2ddl crea el esquema de base de datos la primera vez, y las veces subsiguientes en que la aplicacinrecomienza utilizan dicho esquema. Si usted en algn momento cambia algo del mapeo o del esquema, debe rehabilitarhbm2dll nuevamente para recrear la BD.

    1.3. Parte 2 - Mapear asociaciones

    Hemos mapeado una clase persistente a una tabla. Ahora, partiendo de esta base, agreguemos algunas asociaciones de

    HIBERNATE - Persistencia Relacional para Java Idiomtico http://www.hibernar.org/documentacion_es/castellano.html

    15 de 198 17/02/2009 09:25 a.m.

  • clase. Primero, agregaremos algunas personas a nuestra aplicacin, y almacenaremos una lista de eventos en los cualesparticipan.

    1.3.1. Mapear la clase Person

    El primer bosquejo de la clase Person es simple:

    package events;

    public class Person {

    private Long id; private int age; private String firstname; private String lastname;

    public Person() {}

    // mtodos "getter" y "setter" de acceso, y setter privado para 'id'

    }

    Cree un nuevo archivo de mapeo llamado Person.hbm.xml (y no olvide la referencia a la DTD en la parte superior):

    Por ltimo, agreguemos el nuevo archivo de mapeo a la configuracin de Hibernate.

    Y ahora crearemos una asociacin entre estas dos entidades, Obviamente, las personas pueden participar en eventos, y loseventos tienen participantes. Las cuestiones de diseo con las que tenemos que lidiar son: multiplicidad, direccionalidad, ycomportamiento de las colecciones.

    1.3.2. Una asociacin unidireccional basada en un Set

    Agregaremos una coleccin de eventos a la clase Person. De este modo podremos navegar cmodamente los eventos parauna determinada persona sin tener que ejecutar una consulta explcita, simplemente llamando aPerson.getEvents().Usamos una coleccin de Java, un Set, porque esta coleccin no contendr elementos duplicados, y el orden no esrelevante para nosotros.

    Necesitamos una asociacin unidireccional y de varios valores, que pueda ser implementada con un Set. Escribamos elcdigo para esto en las clases de Java, y luego mapemoslas.

    public class Person {

    private Set events = new HashSet();

    public Set getEvents() { return events; }

    public void setEvents(Set events) { this.events = events; }

    HIBERNATE - Persistencia Relacional para Java Idiomtico http://www.hibernar.org/documentacion_es/castellano.html

    16 de 198 17/02/2009 09:25 a.m.

  • }Antes de mapear esta asociacin, piense en el otro lado (los eventos). Claramente, podemos simplemente mantener estaasociacin unidireccional. O si no, podramos crear otra coleccin en la clase Event, si deseamos navegar en formabidireccional, es decir, anEvent.getParticipants(). Esto no es estrictamente necesario, desde un punto de vistafuncional, siempre se puede ejecutar una consulta explcita para obtener los participamntes de un determinado evento.Esta es una opcin de diseo que le dejamos a usted; pero lo que sacamos en limpio de esta discusin, es la multiplicidadde la asociacin: hay "muchos valores" desde ambos lados. A esto se lo llama una asociacin "de-muchos-a-muchos"(many-to-many). Por esto, usamos el mapeo many-to-many de Hibernate.

    Hibernate soporta todo tipo de mapeos de coleccn, siendo el "set" el ms comn. Para una asociacin "many-to-many",o relacin entre entidades, se necesita una tabla de asociacin. Cada registro de esta tabla simboliza un vnculo entre unapersona y un evento. El nombre de esta tabla se configura con el atributo table del elemento set. La columnaindentificadora por el lado de las personas, se define con el elemento , el nombre de la columna por el lado de loseventos, con el atributo column del . Usted tambin debe decirle a Hibernate la clase de objetos de sucoleccin.

    El esquema de base de datos para este esquema es, entonces:

    _____________ __________________ | | | | _____________ | EVENTS | | PERSON_EVENT | | | |_____________| |__________________| | PERSON | | | | | |_____________| | *EVENT_ID | | *EVENT_ID | | | | EVENT_DATE | | *PERSON_ID | | *PERSON_ID | | TITLE | |__________________| | AGE | |_____________| | FIRSTNAME | | LASTNAME | |_____________|

    1.3.3. Trabajar con asociaciones

    Juntemos a alguna gente con sus eventos, en un nuevo mtodo de 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();}

    Despus de cargar una Person y un Event, simplemente modifique la coleccin usando los mtodos normales de lascolecciones. Como puede usted ver, no hay llamados explcitos a update() o a save(), Hibernate detectaautomticamente que la coleccin ha sido modificada y necesita ser actualizada. Esto se llama "dirty checkingautomtico", y usted puede experimentar con ello cmabiando la propiedad "date" en cualquiera de sus objetos. Siempre ycuando se mantengan en un estado persistente (es decir, ligados a una sesin de Hibernate, por haber sido cargados o

    HIBERNATE - Persistencia Relacional para Java Idiomtico http://www.hibernar.org/documentacion_es/castellano.html

    17 de 198 17/02/2009 09:25 a.m.

  • grabados en una unidad de trabajo), Hibernate monitorear cualquier cambio y ejecutar SQL entre bambalinas. Elproceso de sincronizar el estado de lo que est en memoria con la base de datos, generalmente al final de la unidad detrabajo, se denomina "nivelar, desagotar" la sesin (en ingls, flush). En nuestro cdigo, la unidad de trabajo termina conun "commit" (o "rollback") de la transaccin de base de datos, tal como se define por la opcin de configuracin threadpara la clase CurrentSessionContext.

    Se podra, por supuesto, cargar personas y eventos en distintas unidades de trabajo. O modificar un objeto fuera de unasesin, cuando no est en estado persistente (si lo estuvo anteriormente, este estado se llama "desprendido", en inglsdetached). Incluso una coleccin se puede modificar estando en este estado desprendido.

    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();

    // fin de la primera unidad de trabajo

    aPerson.getEvents().add(anEvent); // aPerson (and its collection) is detached

    // comienzo de la segunda unidad de trabajo

    Session session2 = HibernateUtil.getSessionFactory().getCurrentSession(); session2.beginTransaction();

    session2.update(aPerson); // reasociacin de aPerson, que estaba desprendida

    session2.getTransaction().commit();}

    El llamado a update convierte de nuevo en persistente un objeto que estaba desprendido. Se podra decir que lo liga a unanueva unidad de trabajo, de manera que cualquier modificacin que se le hubiera hecho mientras estaba desprendidopueda ser grabada en la base de datos. Esto incluye cualquier modificacin que se le hubiera hecho a la coleccin de eseobjeto entidad.

    Bueno, esto no es muy til en la situacin actual, pero es un concepto importante, que usted puede aplicar al diseo de supropia aplicacin. Por ahora, simplemente complete este ejercicio agregando una nueva accin al mtodo main() deEventManager, e invquelo desde la lnea de comandos. Si necesita los identificadores de una persona y de un evento, elmtodo save() los devuelve (tal vez usted deba modificar alguno de los mtodos previos, para que devuelvan dichoidentificador).

    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);}

    ste fue un ejemplo de una asociacin entre dos clases igualmente importantes, dos "entidades". Como se mencionanteriormente, hay otras clases y tipos "menos importantes" en un modelo tpico. Algunos, usted ya los ha visto, como losint o String. A esas clases las llamamos value types, y sus instancias dependen de una entidad en particular. Lasinstancias de estos tipos no tienen su propia identidad, ni se pueden compartir entre entidades (dos personas no pueden,por ejemplo, hacer referencia al mismo objeto firstname o primer nombre, incluso si son tocayos). Por supuesto, estosvalue types pueden ser encontrados no solamente en la JDK. De hecho, en una aplicacin Hibernate todas las clases JDKson consideradas "value types", pero usted puede escribir sus propias clases dependientes, para representar una direccino una cantidad de dinero, por ejemplo.

    Tambin se puede disear una coleccin de "value types". Esto es conceptualmente bien distinto de una coleccin dereferencias a otras entidades, pero en el cdigo Java ambas se ven casi igual.

    1.3.4. Coleccin de valores

    HIBERNATE - Persistencia Relacional para Java Idiomtico http://www.hibernar.org/documentacion_es/castellano.html

    18 de 198 17/02/2009 09:25 a.m.

  • Agreguemos una coleccin de objetos "value type" a la entidad Person. Queremos almacenar direcciones de correoelectrnico (email), de manera que el tipo que usaremos es String, y la coleccin, de nuevo un Set.

    private Set emailAddresses = new HashSet();

    public Set getEmailAddresses() { return emailAddresses;}

    public void setEmailAddresses(Set emailAddresses) { this.emailAddresses = emailAddresses;}

    El mapeo de este Set:

    La diferencia, comparada con el mapeo anterior, es la parte element, la cual le dice a Hibernate que la coleccin nocontiene referencias a otra entidad, sino a una coleccin de elementos de tipo string (al estar con minscula nos damoscuenta de que es un tipo/conversor de Hibernate). Une vez ms, el atributo table del set determina el nombre de la tablapara la coleccin. El elemento key define el nombre de columna para la clave fornea, El atributo column de "element"define en dnde estas cadenas van a ser almacenadas.

    Echmosle un vistazo al nuevo esquema de DB

    _____________ __________________ | | | | _____________ | EVENTS | | PERSON_EVENT | | | ___________________ |_____________| |__________________| | PERSON | | | | | | | |_____________| | PERSON_EMAIL_ADDR | | *EVENT_ID | | *EVENT_ID | | | |___________________| | EVENT_DATE | | *PERSON_ID | | *PERSON_ID | | *PERSON_ID | | TITLE | |__________________| | AGE | | *EMAIL_ADDR | |_____________| | FIRSTNAME | |___________________| | LASTNAME | |_____________|

    Se puede ver que la clave primaria de la tabla de la coleccin es, en realidad, una clave compuesta, que usa ambascolumnas. Esto tambin implica que no puede haber direcciones de email duplicadas para una misma persona, lo cual esprecisamente la semntica de un conjunto o "Set" en Java.

    Ahora podemos intentar agregar elementos a esta coleccin, igual que como hicimos antes al vincular personas y eventos.El cdigo Java es el mismo:

    private void addEmailToPerson(Long personId, String emailAddress) {

    Session session = HibernateUtil.getSessionFactory().getCurrentSession(); session.beginTransaction();

    Person aPerson = (Person) session.load(Person.class, personId);

    // el getEmailAddresses() podra disparar una carga "haragana" de la coleccin aPerson.getEmailAddresses().add(emailAddress);

    session.getTransaction().commit();}

    Esta vez, no utilizamos una consulta con fetch para inicializar la coleccin. De ah que la invocacn de su mtodo "getter"disparar un SELECT adicional para inicializarla, de manera que podamos agregarle un elemento. Monitoree el log deSQL e intente optimizar esto con un "eager fetch" (captura ansiosa).

    1.3.5. Asociaciones bidireccionales

    Acto seguido, vamos a mapear una asociacin bidireccional, es decir, vamos a hacer que la asociacin funcione desde

    HIBERNATE - Persistencia Relacional para Java Idiomtico http://www.hibernar.org/documentacion_es/castellano.html

    19 de 198 17/02/2009 09:25 a.m.

  • ambos lados en Java. Desde luego, el esquema de base de datos no cambia, todava tenemos una multiplicidad de-muchos-a-muchos (many-to-many). Una base de datos relacional es ms flexible que un lenguaje de programacin, no necesitacosas como una "direccin de navegacin", los datos pueden ser adquiridos de cualquier manera posible.

    Primero, agregue una coleccin de participantes al cdigo de la clase Event.

    private Set participants = new HashSet();

    public Set getParticipants() { return participants;}

    public void setParticipants(Set participants) { this.participants = participants;}

    Ahora, mapee tambin este lado de la asociacin, en Event.hbm.xml.

    Como puede ver, stos son mapeos set normales en ambos documentos de mapeo. Fjese en que los nombres de columnaen ambos documentos han sido alternados. La adicin ms importante es el atributo inverse="true" en el elemento setdel mapeo de la coleccin de Event.

    Lo que esto significa, es que Hibernate debera rferirse al otro lado (el lado "Person"), cuando necesite obtenerinformacin sobre el vnculo entre los dos. Esto ser ms fcil de entender una vez que veamos cmo se crea el vnculobidireccional entre las dos entidades.

    1.3.6. Trabajar con vnculos bidireccionales

    Primero que nada, tenga en cuenta que Hibernate no afecta la semntica normal de Java, Cmo habiamos creado unvnculo entre personas y eventos en el ejemplo unidireccional? Agregando una instancia de Event a la coleccin dereferencias contenida en una instancia de Person. As que, obviamente, si queremos que este vnculo funcione tambin ensentido inverso, tenemos que hacer lo mismo del otro lado: agregar una referencia a Person a la coleccin en Event. Estode "establecer el vnculo de los dos lados" es absolutamente necesario, y usted jams debe olvidarse de hacerlo.

    Muchos programadores trabajan "defensivamente", y crean mtodos facilitadores que asignan correctamente los vnculosa ambos lados. Por ejemplo, en la clase 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);}

    Fjese en que los mtodos "get" y "et" de la coleccin ahora son "protected" - esto les permite a las clases en el mismopaquete, y a las subclases, acceder a los mtodos, pero les impide a todos los dems inmiscuirse con estas coleccionesdirectamente (bueno... casi). Usted debera, probablemente, hacer lo mismo con las colecciones del otro lado.

    Y qu hay del atributo de mapeo inverse? Para usted (y para Java), un vnculo bidrecciolal es simplemente cuestin deasignar correctamente las referencias en ambos lados .Hibernate, sin embargo, no tiene informacin suficiente como paraorganizar adecuadamente sus llamados a comandos SQL INSERT y UPDATE. Marcar uno de los lados de la asociacincomo inverse, bsicamente le dice a Hibernate que lo ignore, que lo considere como un espejo de lo que ocurre en el otro

    HIBERNATE - Persistencia Relacional para Java Idiomtico http://www.hibernar.org/documentacion_es/castellano.html

    20 de 198 17/02/2009 09:25 a.m.

  • lado. Eso es todo lo que se necesita para que Hibernate resuelva todos los problemas que derivan de transformar unmodelo de navegacin bidireccional en un esquema de base de datos. Las reglas que usted denbe recordar son son simples:Toda asociacin bidireccional necesita que uno de sus lados sea "inverse". En una asociacin de-uno-a-muchos(one-to-many) tiene que ser el lado "many". En una asociacin de-muchos-a-muchos (many to many), elija cualquier lado,da lo mismo.

    1.4. Parte 3 - La aplicacin de web "EventManager"

    Convirtamos la siguiente discusin en una pequea aplicacin de web.

    Una aplicacin de web Hibernate utiliza sesiones y transacciones, lo mismo que la aplicacim autosuficiente que vimosanteriormente. Sin embargo, es conveniente usar algunos patrones de programacin ("patterns"). Escribamos un servletEventManagerServlet que pueda listar los eventos alamacenados en la base de datos, y provea un formulario HTMLpara ingresar nuevos eventos.

    1.4.1. Escribir el servlet bsico

    Cree una nueva clase en su directorio de cdigo fuente, en el paquete events:

    package events;

    // Imports

    public class EventManagerServlet extends HttpServlet {

    // Servlet code}

    Este servlet maneja requests HTTP del tipo GET solamente, as que el mtodo que implementamos es doGet():

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

    SimpleDateFormat dateFormatter = new SimpleDateFormat("dd.MM.yyyy");

    try { // comienzo nuestra unidad de trabajo HibernateUtil.getSessionFactory().getCurrentSession().beginTransaction();

    // procesamiento de la solicitud (request) y presentacin de la pgina...

    // fin de la unidad de trabajo HibernateUtil.getSessionFactory().getCurrentSession().getTransaction().commit();

    } catch (Exception ex) { HibernateUtil.getSessionFactory().getCurrentSession().getTransaction().rollback(); throw new ServletException(ex); }

    }

    El "pattern" o patrn de programacn que estamos aplicando aqu se llama session-per-request, (una sesin por cada"solicitud" o request HTTP). Cuando una nueva request apela al servlet, se abre una nueva sesin de Hibernate medianteel primer llamado a getCurrentSession() de la SessionFactory. Entonces, ss inicia una transaccin de base de datos(todo el cdigo de acceso a datos ocurre dentro de la transaccin, no importa si para lectura o escritura; en las aplicacionesno usamos auto-commit).

    Nunca cree una nueva sesin de Hibernate para cada operacin de base de datos. Use una sesin de Hibernate a lo largode toda la request, es decir, que tenga un "alcance" de toda la sesin. Use getCurrentSession(), de manera que quedeautomticamente ligada al Thread actual.

    A continuacin, las acciones posibles de la request son procesadas, y es generada la respuesta HTML. Enseguida nosdedicaremos a esa parte.

    Finalmente, la "unidad de trabajo" finaliza, cuando el procesamiento y presentacin hayan sido completados. Si ocurrialgn problema durante este procesamiento o presentacin, se lanzar una excepcin y la se ejecutar un "rollback" de la

    HIBERNATE - Persistencia Relacional para Java Idiomtico http://www.hibernar.org/documentacion_es/castellano.html

    21 de 198 17/02/2009 09:25 a.m.

  • transaccin. Esto cubre el "pattern" session-per-request. En lugar de escribir cdigo para demarcar la transaccin encada request, usted debera crea un Servlet Filter. Refirase al sitio de web de Hibernate y a la Wiki para ms informacinacerca de este "pattern", llamado Open Session in View u OSIV, algo as como "apertura de una sesin por cada vista".Este patrn se necesitar en cuanto usted considere presentar sus "vistas" usando JSP en lugar de servlets.

    1.4.2. Procesamiento y presentacin

    Implementemos el procesamiento de la solicitud y la presentacin de la pgina.

    // escribe el header encabezado HTML

    PrintWriter out = response.getWriter();out.println("Event Manager");

    // maneja las acciones

    if ( "store".equals(request.getParameter("action")) ) {

    String eventTitle = request.getParameter("eventTitle"); String eventDate = request.getParameter("eventDate");

    if ( "".equals(eventTitle) || "".equals(eventDate) ) { out.println("Please enter event title and date."); } else { createAndStoreEvent(eventTitle, dateFormatter.parse(eventDate)); out.println("Added event."); }}

    // imprime la pginaprintEventForm(out);listEvents(out, dateFormatter);

    // escribe el pie HTMLout.println("");out.flush();out.close();

    Concedido, este tipo de escritura de cdigo, mezclando Java y HTML, sera inadmisible en aplicaciones ms complejas,tenga en cuenta que slo estamos ilustrando conceptos bsicos de Hibernate en este instructivo. El cdigo imprime unencabezado y un pie de pgina en HTML. Dentro de la pgina propiamente dicha, se imprime un formulario (form) para elingreso de eventos. El primer mtodo es trivial, y slo produce HTML:

    private void printEventForm(PrintWriter out) { out.println("Add new event:"); out.println(""); out.println("Title: "); out.println("Date (e.g. 24.12.2009): "); out.println(""); out.println("");}

    El mtodo listEvents() usa la sesin de Hibernate ligada al Thread actual para ejecutar una consulta:

    private void listEvents(PrintWriter out, SimpleDateFormat dateFormatter) {

    List result = HibernateUtil.getSessionFactory().getCurrentSession().createCriteria(Event.class) if (result.size() > 0) { out.println("Events in database:"); out.println(""); out.println(""); out.println("Event title"); out.println("Event date"); out.println(""); for (Iterator it = result.iterator(); it.hasNext();) { Event event = (Event) it.next(); out.println(""); out.println("" + event.getTitle() + ""); out.println("" + dateFormatter.format(event.getDate()) + ""); out.println(""); } out.println(""); }

    HIBERNATE - Persistencia Relacional para Java Idiomtico http://www.hibernar.org/documentacion_es/castellano.html

    22 de 198 17/02/2009 09:25 a.m.

  • }Finalmente, la accin store es despachada al mtodo createAndStoreEvent(), el cual usa la sesin del Thread actual.

    protected void createAndStoreEvent(String title, Date theDate) { Event theEvent = new Event(); theEvent.setTitle(title); theEvent.setDate(theDate);

    HibernateUtil.getSessionFactory().getCurrentSession().save(theEvent);}

    Eso es todo. El servlet est completo. Una request al servlet ser procesada en una nica sesin y transaccin. Tal comoocurri en el ejemplo anterior, Hibernate puede ligar estos objetos al Thread actual de ejecucin. Esto le da a usted lalibertad de acceder a la SessionFactory de cualquier manera que guste. Normalmente, usted usara un diseo mssofisticado, y movera el cdigo de acceso a datos (DAO, por sus siglas en ingls) a otra "capa". Refirase a la Wiki deHibernate para ms ejemplos.

    1.4.3. Despliegue (deploy) y test

    Para desplegar (deploy) esta aplicacin, tiene que crear un archivo ".war". Agregue la siguiente target de Ant a su archivobuild.xml:.

    Esta target crea un archivo llamado hibernate-tutorial.war en su directorio de proyecto. Empaqueta todas lasbibliotecas y el descriptor web.xml, el cual se espera que est en el directorio base de su proyecto.

  • 1.5. Sumario

    Este instructivo cubri lo bsico para escribir una simple aplicacin Hibernate autosuficiente, y una pequea aplicacin deWeb.

    Si ya va tomando confianza con Hibernate, contine hojeando la tabla de contenidos en la documentacin de referencia,buscando temas que le interesen. Los ms solicitados son el procesamiento de transacciones (Captulo 11, Transacciones yConcurrencia), la performance de las capturas de datos o "fetch performance" (Captulo 19, Mejorar la performance), eluso de las API (interfaces de programacin) (Captulo 10, Trabajar con objetos) y las caractersticas de las consultas(Seccin 10.4, Consultar).

    No olvide chequear el sitio de web de Hibernate en busca de ms instructivos especializados.

    Captulo 2. Arquitectura

    2.1. Generalidades

    Una vista a vuelo de pjaro de la arquitectura de Hibernate

    Este diagrama muestra a Hibernate usando datos de configuracin y base de datos para proveerle servicios de persistencia(y objetos persistentes) a la aplicacin.

    Nos gustara mostrar una vista ms detallada de la arquitectura en tiempo de ejecucin. Lamentablemente, Hibernate estan flexible, que soporta muchas estrategias. Vamos a mostrar los dos extremos: la arquitectura "liviana" fuerza a laaplicacin a proveer sus propias conexiones JDBC y a gerenciar sus propias tranascciones. Esta arquitectura usa unsubconjunto mnimo de las APIs de Hibernate.

    HIBERNATE - Persistencia Relacional para Java Idiomtico http://www.hibernar.org/documentacion_es/castellano.html

    24 de 198 17/02/2009 09:25 a.m.

  • La arquitectura "con todas las luces" abstrae la aplicacin, alejndola de las capas subyacentes de JDBC/JTA, y deja queHibernate se encargue de los detalles.

    He aqu algunas definiciones de los objetos en los diagramas:

    SessionFactory (org.hibernate.SessionFactory)

    Un cach thread-safe e inmutable de mapeos, compilados para una base de datos en particular. Una fbrica (factory)de sesiones, y cliente de ConnectionProvider. Puede contener un cach optativo (llamado "de 2do nivel") que esreusable entre transacciones, a nivel de proceso o de cluster.

    Session (org.hibernate.Session)

    Un objeto de thread simple y de corta visa, que representa una conversacin entre la aplicacin y el repositoriopersistente. Envuelve a una fbrica de conexiones JDBC por transaccin. Contiene un cach obligatorio (llamado"de primer nivel") de objetos persistentes, que se usa al navegar el rbol de objetos, o cuando se buscan los objetospor identificador.

    Objetos y colecciones persistentes

    Objetos de un solo thread y corta vida, que contienen "estado" persistente y cumplen una funcin de negocio.Pueden ser JavaBeans comunes, o puros y simples objetos de Java (POJOs por sus siglas en ingls), la nicacaracterstica notable que tienen, es que estn asociados con una sesin. En cuanto la sesin se cierra, serndesprendidos, y quedarn listos para ser usados en cualquier capa de la aplicacin (por ejemplo, directamente comoobjetos de transmisin de datos o "DTOs", desde y hacia la capa de presentacin).

    HIBERNATE - Persistencia Relacional para Java Idiomtico http://www.hibernar.org/documentacion_es/castellano.html

    25 de 198 17/02/2009 09:25 a.m.

  • Objetos y colecciones transitorios y desprendidos

    Instancias de clases persistenteses que, por el momento, no estn asociadas con una sesin. Pudieron haber sidoinstanciadas por la aplicacn, y an no haber sido asociadas con una sesin, o bien haber sido instanciadas por unasesin que en ese momento est cerrada.

    Transaccin (org.hibernate.Transaction)

    (Optativo) un objeto de un solo thread y corta vida, usado por la aplicacon para especificar unidades atmicas detrabajo. Abstrae a la aplicacin de la transaccin JDBC, JTA o CORBA subyacente. Una sesn puede extenderse alo largo de varias transacciones en algunos casos. Pero, sea como sea, el cdigo para demarcar transacciones (yasea utilizando APIs subyancentes o la interfaz Transaction) nunca es optativo!

    ConnectionProvider (org.hibernate.connection.ConnectionProvider)

    (Optativo) Una fbrica y repositorio (pool) de conexiones JDBC. Abstrae la aplicacin de la fuente de datos(Datasource) o del gerente de driver (DriverManager) subyacentes. No est expuesto directamente a la aplicacin,pero puede ser implementado o extendido por el programador.

    TransactionFactory (org.hibernate.TransactionFactory)

    (Optativo) Una fbrica de instancias de Transaction. No est expuesta directamente a la aplicacin, pero puede serimplementada o extendida por el programador.

    Interfaces de extensin

    Hibernate ofrece varias interfaces de extensin optativoes, se pueden implementar para personalizar elcomportamiento de la capa de persistencia. Vea la documentacin de la API para ms detalles.

    En la arquitectura "liviana", la aplicacin se saltea las APIs de Transaction/TransactionFactory y/oConnectionProvider APIs para dialogar con JTA o JDBC directamente.

    2.2. Estados de una instancia

    Una instancia de una clase persistente puede estar en uno de tres estados diferentes, los cuales se definen con respecto aun contexto de persistencia: la sesin.

    transitorio (transient)

    La instancia no est asociada con ningn "contexto de persistencia" (sesin), ni nunca lo ha estado. Carece de"identidad persistente", es decir, de clave primaria.

    persistente (persistent)

    La instancia est al momento asociada con un contexto de persistencia. Tiene identidad persistente (valor de claveprimaria) y, tal vez, un valor correspondiente en la base de datos. Para un contexto de persistencia determinado,Hibernate garantiza que la identidad persistente equivale a la "identidad Java" (ubicacin en memoria del objeto).

    desprendida (detached)

    La instancia estuvo alguna vez asociada con un contexto de persistencia, pero dicho contexto est cerrado, o lainstancia ha sido serializada a otro proceso. Tiene una identidad persistente y, tal vez, el correspondiente registro enla base de datos. Hibernate no ofrece ninguna garanta acerca de la relacin entre identida persistente e identidadJava.

    2.3. Integracin con JMX

    JMX es el estndar de J2EE para la administracin de componentes Java. Hibernate puede ser administrado via un servicioJMX estndar. Nosotros proveemos una implementacin de MBean en la distribucin:org.hibernate.jmx.HibernateService.

    Para un ejemplo sobre cmo desplegar Hibernate como un servicio JMX en el servidor de aplicaciones JBoss, por favorvea la gua del usuario de JBoss. En el servidor de applicaciones JBoss, tambin se obtienen los siguientes beneficios si se

    HIBERNATE - Persistencia Relacional para Java Idiomtico http://www.hibernar.org/documentacion_es/castellano.html

    26 de 198 17/02/2009 09:25 a.m.

  • despliega (deploy) usando JMX:

    Manejo de sesiones: El ciclo de vida de una sesin de Hibernate puede ser automticamente ligado al alcance(scope) de una transaccin JTA. Esto significa que usted ya no necesita abrir y cerrar manualmente las sesiones, deesto se encarga el interceptor de JBoss. Tampoco debe preocuparse ya por demarcar la transaccin en su cdigo (amenos que quiera escribir usted mismo una capa de persistencia porttil, use la API Transaction de Hibernate paraeso). Puede llamar a HibernateContext para acceder a una sesin.

    Despliegue del Archivo de Hibernate (HAR por sus siglas en ingls): Normalmente se despliega el servicio JMX deHibernate usando el "descriptor de despliegue" (deployment descriptor), en un archivo EAR o SAR, el cual soportalas opciones de configuracin de una SessionFactory de Hibernate. De todos modos, para esto an se debenombrar a todos los archivos de mapeo en el descriptor de despliegue. En cambio, si decide usar el despliegue HAR,JBoss detecta automticamente todos los archivos de mapeo en su archivo HAR.

    Consulte la gua del usuario del servidor de aplicaciones JBoss para mayor informacin acerca de estas opciones.

    Otra caracterstica disponible en forma de servicio JMX son las estadsticas de Hibernate en tiempo de ejecucin. Vea laSeccin 3.4.6, Estadsticas de Hibernate

    2.4. Soporte de JCA

    Hibernate tambin puede ser configurado como un conector JCA. Por favor, vea el sitio de web para ms detalles, peronote que el soporte Hibernate de JCA se considera todava experimental.

    2.5. Sesiones contextuales

    La mayora de las aplicaciones que usan Hibernate necesitan alguna forma de sesin "contextual", donde una sesindeterminada est en efecto a lo largo del "scope" o alacance de un contexto determinado. De todos modos, entre lasdistintas aplicaciones, la definicin de lo que constituye un "contexto" suele diferir, as como la definicin de quconstituye el contexto "actual". Las aplicaciones que usaban Hibernate antes de la versin a 3.0, tendan a utilizar o bienversiones "caseras" de sesin contextual (basadas en ThreadLocal) o bien utilizaban frameworks de terceras partes (comoSpring o Pico), los cuales provean sesiones contextuales basadas en proxies e intercepcin.

    Empezando con la versin 3.0.1, Hibernate incorpor el mtodo SessionFactory.getCurrentSession(). Inicialmente,este mtodo asuma el uso de transacciones JTA, donde la transaccin JTA defina tando el alcance como el contexto de lasesin actual.El equipo de Hibernate mantiene que, dada la madurez de las numerosas implementaciones autosuficientes de JTA queexisten hoy da, la mayora (si no todas) las aplicaciones deberan estar usando JTA para su manejo de transacciones (estno no desplegadas en un contenedor J2EE). Basndose en eso, las sesiones contextuales JTA son todo lo que usted deberanecesitar usar.

    Sin embargo, a partir de la versin 3.1, el proceso que ocurre por detrs de SessionFactory.getCurrentSession() esconfigurable. Con este fin, una nueva interfaz de extensin (org.hibernate.context.CurrentSessionContext) y unnuevo parmetro de configuracin (hibernate.current_session_context_class) han sido agregados, para permitir"enchufar" implementaciones nuevas para definir el alcance y contexto de las sesiones.

    Vea los Javadocs acerca de la interfaz org.hibernate.context.CurrentSessionContext, para una descripcindetallada del contrato que sta implica. Define un solo mtodo, currentSession(), por el cual la implementacin esresponsable de rastrear la sesin contextual actual. Hibernate ya viene con 3 implementaciones incuidas de esta interfaz.

    org.hibernate.context.JTASessionContext - las sesiones actuales son localizadas y su alcance definido poruna transaccin JTA. El procesamiento aqu es exactamente el mismo que en el antiguo enfoque slo-JTA. Vea losJavadocs para ms detalles.

    org.hibernate.context.ThreadLocalSessionContext - las sesiones actuales son localizadas por thread deejecucin. De nuevo, vea los Javadocs para ms detalles.

    org.hibernate.context.ManagedSessionContext - las sesiones actuales son localizadas por thread de ejecucin.Sin embargo, usted es responsable por ligar y desligar las instancias de sesin, mediante mtodos estticos en estaclase. Nunca abre, cierra o le aplica flush a una sesin.

    Las dos primeras implementaciones proveen un modelo de programacin del tipo "una sesin - una transaccin de base de

    HIBERNATE - Persistencia Relacional para Java Idiomtico http://www.hibernar.org/documentacion_es/castellano.html

    27 de 198 17/02/2009 09:25 a.m.

  • datos", tambin llamado session-per-request. El comienzo y fin de una sesin de Hibernate est definido por la duracinde la transaccin de base de datos. Si usted usa demarcacin programtica de transacciones, en simple JSE sin JTA, se leaconseja que use la API de Transaction de Hibernate, para ocultar el sistema de transacciones subyacente. Si el cdigose est ejecutando en un contenedor EJB que soporte CMT, los lmites de la transaccin son definidos declarativamente, yusted no necesita ninguna transaccin ni demarcacin de operaciones en el cdigo propiamente dicho. Refirase alCaptulo 11, Transacciones y Concurrencia para ms informacin y ejemplos de cdigo.

    El parmetro de configuracin hibernate.current_session_context_class define cul implementacin deorg.hibernate.context.CurrentSessionContext debe ser usada. Note que, por compatibilidad con versionesanteriores, si este parmetro de configuracin no se asigna, sino que se configuraorg.hibernate.transaction.TransactionManagerLookup en su lugar, Hibernate usar elorg.hibernate.context.JTASessionContext. Tpicamente, el valor de este parmetro simplemente nombra la clase deimplementacin a usar; para las tres implementaciones de fbrica existen los respectivos nombres cortos: "jta", "thread" y"managed".

    Captulo 3. Configuracin

    Como Hibernate est diseado para operar en varios entornos diferentes, hay un gran nmero de parmetros deconfiguracin. Afortunadamente, la mayora tiene valores por defecto razonables, e Hibernate es distribuido con unarchivo hibernate.properties de ejemplo en el directorio etc/, que muestra varias de las opciones. Simplementecoloque este ejemplo en su classpath y modifquelo a medida.

    3.1. Configuracin programtica

    Una instancia de org.hibernate.cfg.Configuration representa un conjunto completo de mapeos desde los tipos Javade una aplicacin, hacia una base de datos SQL. org.hibernate.cfg.Configuration se usa para construir unaorg.hibernate.SessionFactory inmutable. Los mapeos son compilados a partir de los varios archivos de mapeo XML.

    Se puede ontener una instancia de org.hibernate.cfg.Configuration instancindola directamente, y especificando losarchivos de mapeo XML. Si los archivos de mapeo estn en el classpath, utilice addResource():

    Configuration cfg = new Configuration() .addResource("Item.hbm.xml") .addResource("Bid.hbm.xml");

    Una alternativa (a veces preferible), es especificar la clase mapeada, y dejar que Hibernate encuentre el documento demapeo l solo:

    Configuration cfg = new Configuration() .addClass(org.hibernate.auction.Item.class) .addClass(org.hibernate.auction.Bid.class);

    Entonces Hibernate buscar archivos de mapeo llamados /org/hibernate/auction/Item.hbm.xml y /org/hibernate/auction/Bid.hbm.xml en el calsspath. Este enfoque elimina la necesidad de "hardcodear" los nombres de archivo.

    org.hibernate.cfg.Configuration tambin permite especificar propiedades de configuracin:

    Configuration cfg = new Configuration() .addClass(org.hibernate.auction.Item.class) .addClass(org.hibernate.auction.Bid.class) .setProperty("hibernate.dialect", "org.hibernate.dialect.MySQLInnoDBDialect") .setProperty("hibernate.connection.datasource", "java:comp/env/jdbc/test") .setProperty("hibernate.order_updates", "true");

    sta no es la nica manera de pasarle propiedades de configuracin a Hibernate. Entre las muchas otras opciones, estnstas:

    Pasarle una instancia de java.util.Properties a Configuration.setProperties().

    Colocar un archivo llamado hibernate.properties en un directorio raz del classpath.

    Configurar propiedades "de sistema" (System) usando java -Dproperty=value.

    HIBERNATE - Persistencia Relacional para Java Idiomtico http://www.hibernar.org/documentacion_es/castellano.html

    28 de 198 17/02/2009 09:25 a.m.

  • Incluir elementos en hibernate.cfg.xml (se discute ms adelante).

    hibernate.properties es el enfoque ms fcil, si lo que se busca es empezar rpido.

    La idea de org.hibernate.cfg.Configuration es ser un objeto que viva durante el "tiempo de arranque" (startup), paraser descartado luego, una vez que la SessionFactory haya sido creada.

    3.2. Obtener una SessionFactory

    Una vez que todos los mapeos hayan sido revisados por org.hibernate.cfg.Configuration, la aplicacin debe obteneruna fbrica o "SessionFactory" para las instancias de org.hibernate.Session. Esta fbrica ser compartida por todos losthreads que accedan a la aplicacn.

    SessionFactory sessions = cfg.buildSessionFactory();

    Hibernate s le permite a la aplicacin instanciar ms de una org.hibernate.SessionFactory. Esto es til si se estusando ms de una base de datos.

    3.3. Conexiones JDBC

    Usualmente, usted querr que la org.hibernate.SessionFactory cree y administre el "fondo comn" (pool) de sesionespor usted. Si se adopta este enfoque, abrir una org.hibernate.Session es tan simple como escribir:

    Session session = sessions.openSession(); // abre una nueva sesin

    No bien se haga algo que requiera acceso a la base de datos, una nueva conexin JDBC ser obtenida del "pool".

    Para que esto funcione, necesitamos pasarle algunas propiedades de conexin JDBC a Hibernate. Todos los nombres ysemntica de las propiedades Hibernate estn definidos en la clase org.hibernate.cfg.Environment. Vamos a describirlos valores ms importantes para configurar la conexin JDBC.

    Hibernate obtendr las conexiones (y las administrar en un "pool") usando un java.sql.DriverManager si ustedconfigura las siguientes propiedades:

    Table 3.1. Hibernate JDBC Properties

    Nombre de la propiedad Propsitohibernate.connection.driver_class clase del driver JDBC

    hibernate.connection.url URL de JDBC

    hibernate.connection.username usuario de la base de datos

    hibernate.connection.password clave del usuario de la base de datos

    hibernate.connection.pool_size nmero mximo de conexiones en el "pool"

    El algoritmo que ya viene incluido en Hibernate para el "pooling" de conexiones es, sin embargo, bastante rudimentario.Fue concebido ms que nada para ayudarlo a dar los primeros pasos, no para ser usado en un sistema de produccin, nisiquiera para un test de performance. Ustde debera usar un "pool" de algn tercero para asegurar mayor redimiento yestabilidad. Simplemente reemplace la propiedad hibernate.connection.pool_size con propiedades especficas de laherramienta de "pooling" de su eleccin. Esto desactivar el "pooling" interno de Hibernate. Por ejemplo, usted podraelegir C3P0.

    C3P0 es una biblioteca para pool de conexiones distribuida junto con Hibernate en el direactorio lib. Hibernate usar suorg.hibernate.connection.C3P0ConnectionProvider para efectuar el "pooling" de conexiones, si usted les asignavalores a las propiedades que empiezan con hibernate.c3p0.*. Si prefiere usar Proxool, refirase a las propiedadesempaquetadas en hibernate.properties, o al sitio de web de Hibernate para mayor informacin.

    He aqu un ejemplo de un hibernate.properties para C3P0:

    hibernate.connection.driver_class = org.postgresql.Driver

    HIBERNATE - Persistencia Relacional para Java Idiomtico http://www.hibernar.org/documentacion_es/castellano.html

    29 de 198 17/02/2009 09:25 a.m.

  • hibernate.connection.url = jdbc:postgresql://localhost/mydatabasehibernate.connection.username = myuserhibernate.connection.password = secrethibernate.c3p0.min_size=5hibernate.c3p0.max_size=20hibernate.c3p0.timeout=1800hibernate.c3p0.max_statements=50hibernate.dialect = org.hibernate.dialect.PostgreSQLDialect

    Para usar "pooling" dentro de un servidor de aplicaciones, se debera configurar Hibernate de manera tal, que siempreobtenga las conexiones desde una fuente de datos javax.sql.Datasource registrada usando JNDI. Se necesitarn por lomenos las siguientes propiedades:

    Table 3.2. Propiedades para fuente de datos de Hibernate

    Nombre de la propiedad Propsitohibernate.connection.datasource nombre JNDI de la fuente de datos

    hibernate.jndi.url URL del proveedor de JNDI (optativo)

    hibernate.jndi.class clase del InitialContextFactory de JNDI (optativo)

    hibernate.connection.username usuario de la base de datos (optativo)

    hibernate.connection.password clave del usuario de base de datos (optativo)

    He aqu un ejemplo de un archivo hibernate.properties para configurar la fuente de datos JNDI en un servidor deaplicaciones:

    hibernate.connection.datasource = java:/comp/env/jdbc/testhibernate.transaction.factory_class = org.hibernate.transaction.JTATransactionFactoryhibernate.transaction.manager_lookup_class = org.hibernate.transaction.JBossTransactionManagerLookuhibernate.dialect = org.hibernate.dialect.PostgreSQLDialect

    Las conexiones JDBC que se obtengan de una fuente de datos JNDI participarn automticamente de las transacciones"manejadas por el contenedor" del servidor de aplicaciones.

    Tambin se pueden agregar propiedades de conexin arbitrarias, afijando "hibernate.connection" al nombre de lapropiedad de conexin. Por ejemplo, usted puede especificar una propiedad de conexin charSet (juego de caracteres),usando "hibernate.connection.charSet".

    Usted tambin puede definir su propia estrategia de plugin para obtener conexiones JDBC, implementando la interfazorg.hibernate.connection.ConnectionProvider, y especificando su propia implementacin a medida en la propiedadhibernate.connection.provider_class.

    3.4. Propiedades optativas de configuracin

    Hay varias otras propiedades que controlan el comportamiento de Hibernate en tiempo de ejecucin. Todas son optativas,y tienen valores por defecto razonables.

    Advertencia: algunas de estas propiedades existen "a nivel de sistema" solamente. A las propiedades a nivel de sistemaslo se les puede asignar valores via java -Dproperty=value o hibernate.properties. No se les puede asignar valoresusando las tcnicas descritas anteriormente.

    Tabla 3.3. Porpiedades de Configuration de Hibernate

    Nombre de la propiedad Propsito

    hibernate.dialect

    El nombre de clase de un org.hibernate.dialect.Dialect que le permita aHibernate generar SQL optimizado para una BD relacional en particular.

    por ejemplo classname.completo.del.dialecto

    En la mayora de los casos, Hibernate ser capaz de elegir la implementacin dedialecto correcta, basndose en los metadatos devueltos por el driver JDBC.

    Tabla 3.4. Propiedades Hibernate de JDBC y Conexin

    Nombre de la propiedad Propsito

    hibernate.jdbc.fetch_size Un valor distinto de 0 determina el tamao de la captura o "fetch" JDBC (llamaa Statement.setFetchSize()).

    HIBERNATE - Persistencia Relacional para Java Idiomtico http://www.hibernar.org/documentacion_es/castellano.html

    30 de 198 17/02/2009 09:25 a.m.

  • Nombre de la propiedad Propsito

    hibernate.jdbc.batch_size

    Un valor distinto de 0 habilita el uso de actualizacionesn en lotes (batchupdates) de JDBC2 por parte de Hibernate.

    valores posibles se recomienda entre 5 y 30

    hibernate.jdbc.batch_versioned_data

    Asgnele true a esta propiedad, si su driver JDBC devuelve conteos de fila alejecutar executeBatch() (normalmente, es seguro hacerlo). Entonces,Hibernate usar "batched DML" (lenguaje de creacin de datos en lotes) paradatos a los que se les haya asignado automtiacmente nmero de versin. Elvalor por defecto es false.

    valores posibles true | false

    hibernate.jdbc.factory_class

    Selecciona un org.hibernate.jdbc.Batcher hecho a medida. La mayora delas aplicaciones no necesita configurar esta propiedad.

    por ejemplo classname.of.BatcherFactory

    hibernate.jdbc.use_scrollable_resultset

    Habilita el uso de resultados JDBC2 navegables (scrollable resultsets) por partede Hibernate. Esta propiedad slo es necesaria cuando se emplean conexionesJDBC provistas por el usuario. De otro modo, Hibernate usa los metadatos dela conexin.

    valores posibles true | false

    hibernate.jdbc.use_streams_for_binary

    Indica que se usarn streams al leer o escribir cdigo binario, o tiposserializables desde o hacia JDBC. *propiedad a nivel de sistema*

    valores posibles true | false

    hibernate.jdbc.use_get_generated_keys

    Habilita el uso del PreparedStatement.getGeneratedKeys() de