SlideShare ist ein Scribd-Unternehmen logo
1 von 90
Downloaden Sie, um offline zu lesen
HIBERNATE
HIBERNATE




ÍNDICE

1     INTRODUCCIÓN .................................................................................................................... 3
    1.1      Object-Relational Mapping.......................................................................................... 3
    1.2      Hibernate y MVC en entornos web ............................................................................. 5


2     MI PRIMERA APLICACIÓN CON HIBERNATE ......................................................................... 7
    2.1      Pasos para crear una aplicación Hibernate ................................................................. 7
    2.2      Desarrollo paso a paso................................................................................................. 8


3     FRAMEWORK HIBERNATE .................................................................................................. 38
    3.1      Introducción............................................................................................................... 38
    3.2      Instalación.................................................................................................................. 39
    3.3      Configuración............................................................................................................. 39
    3.4      El interfaz Session ...................................................................................................... 58


4     ASOCIACIONES.................................................................................................................... 62
    4.1      Relaciones en Bases de datos .................................................................................... 63
    4.2      Many-to-one .............................................................................................................. 65
    4.3      Many-to-many ........................................................................................................... 67
    4.4      One-to-one................................................................................................................. 69


5     RECUPERACIÓN DE DATOS ................................................................................................. 71
    5.1      HQL ............................................................................................................................ 73
    5.2      Criteria ....................................................................................................................... 83
    5.3      SQL ............................................................................................................................. 89




                                                                                                                                             [2]
HIBERNATE



   1. INTRODUCCIÓN


   1.1.OBJECT-RELATIONAL MAPPING



Hibernate es una implementación de mapeo Objeto-Relacional (ORM – Object-Relational
Mapping). El objetivo de un ORM es hacer corresponder el modelo de datos de la aplicación
con el modelo de clases de la misma, los cuales no son tan distintos como se pueda pensar.

Para ello, Hibernate realiza el mapeo de elementos (tablas, columnas) entre una Base de datos
relacional y objetos de la aplicación en cuestión:




                         Base de Datos Relacional                                Modelo de Objetos


                                TABLA Persona
                                                                                           Persona
                Nombre                Apellido        Teléfono
        Juan                  López              666111122                       -String nombre
                                                                                 -String apellido
        Ana                   Hurtado            959121212
                                                                                 -String teléfono
        Francisco             Soria              889121212
        Belén                 Jiménez            789456123




                                                             instance: Persona

                                                       nombre = Juan
                                                       apellido = López
                                                       teléfono = 666111122




                                                                                                     [3]
HIBERNATE



Este tipo de sistema facilita todas las operaciones de persistencia y acceso a los datos desde la
aplicación al presentar las siguientes características principales:

        Independiente de SQL: Hibernate incorpora funcionalidades para las operaciones
        simples de recuperación y actualización de datos para las cuales no será necesario
        utilizar las sentencias SELECT, INSERT, UPDATE o DELETE habituales, siendo sustituidas
        por llamadas a métodos (list, save, update, delete, …). Hibernate se encarga de
        generar la sentencia SQL que se encargará de realizar tales operaciones. De cualquier
        modo, se pueden especificar consultas SQL en caso necesario o incluso consultas en el
        dialecto de Hibernate, el HQL, con sintaxis similar a SQL pero que establece una serie
        de elementos propios del sistema ORM que gestiona.

        Independiente del SGBD: al aislar las funciones de manipulación de datos del lenguaje
        SQL, se consigue que la aplicación pueda comunicarse con cualquier SGBD ya que no
        existirán dependencias o particularidades en las sentencias de consulta o actualización
        de datos que harían a la aplicación dependiente de un SGBD en cuestión. El encargado
        de realizar la traducción final entre las operaciones Objeto-relacionales y las
        sentencias SQL es Hibernate, con lo cual el problema de la compatibilidad queda
        solventado. Incorpora soporte para la mayoría de los sistemas de bases de datos
        existentes.

        Independiente de JDBC: Hibernate contiene una API completa que aísla a la aplicación,
        no solamente de las operaciones con lenguaje SQL, sino también la utilización de
        objetos propios de la gestión de Bases de datos JDBC (Statement, ResultSet, …). Este
        tipo de objetos habituales en la programación Java de acceso a Bases de datos, se
        sustituye por el uso de objetos mucho más sencillos como colecciones de clases tipo
        JavaBeans que contendrán los datos de los almacenes de datos.




                                                                                              [4]
HIBERNATE



    1.2.HIBERNATE Y MVC EN ENTORNOS WEB



En una arquitectura MVC genérica como la siguiente, Hibernate juega un papel primordial
como capa de persistencia de la aplicación. Como aparece en el esquema, los JavaBeans
encargados de ejecutar la lógica de la aplicación interacturán con datos habitualmente
almacenados en una Base de datos. Hibernate se introduce en este contexto para dar soporte
de acceso y gestión de los datos a la capa de Modelo.




El patrón MVC se utiliza de forma amplia en el desarrollo de aplicaciones web.




Fuente: http://java.sun.com/blueprints/patterns/MVC-detailed.html



                                                                                       [5]
HIBERNATE



Controller (Controlador):

        Servlet central que recibe las peticiones, procesa la URL recibida y delega el
        procesamiento a los JavaBeans.
        Servlet que almacena el resultado del procesamiento realizado por los JavaBeans en el
        contexto de la petición, la sesión o la aplicación.
        Servlet que transfiere el control a un JSP que lleva a cabo la presentación de
        resultados.



Model (Modelo):

       JavaBeans (o EJBs para aplicaciones más escalables) que desempeñan el rol de modelo:
                Algunos beans ejecutan lógica.
                Otros guardan datos.
        Normalmente:
                El Servlet Controller invoca un método en un bean de lógica y éste devuelve un
                bean de datos.
                El programador del JSP tiene acceso a beans de datos.



View (Vista):

        Rol ejecutado por JSPs.
        El Servlet Controller transfiere el control al JSP después de guardar en un contexto el
        resultado en forma de un bean de datos.
        JSP usa jsp:useBean y jsp:getProperty para recuperar datos y formatear respuesta en
        HTML o XML.



En resumen:

        Los JavaBeans o EJBs ejecutan la lógica de negocio y guardan los resultados.
        Los JSPs proporcionan la información formateada.
        Los servlets coordinan/controlan la ejecución de los beans y los JSPs.




                                                                                            [6]
HIBERNATE



    2. MI PRIMERA APLICACIÓN CON HIBERNATE


Esta parte del manual es una guía paso a paso para realizar una aplicación sencilla, es tal vez la
mejor manera de introducirse con Hibernate y es recomendable realizarla antes de leer el
resto del manual ya que mejorará la comprensión de éste.

Esta aplicación será desarrollada haciendo uso del IDE Netbeans 6.7. Se puede descargar de
http://netbeans.org/.




    2.2.PASOS PARA CREAR UNA APLICACIÓN HIBERNATE



Estos son los pasos mínimos que se deberán seguir para desarrollar la aplicación
satisfactoriamente.

    1. Determinar el modelo de datos de la aplicación.
    2. Añadir las librerías Java de Hibernate.
    3. Definir las clases de persistencia.
    4. Crear los ficheros de mapeo.
    5. Configurar Hibernate.
    6. Crear clases de ayuda.
    7. Cargar y guardar objetos.
    8. Ejecutar la primera versión.
    9. Asociar clases.
    10. Ejecutar la aplicación.




                                                                                               [7]
HIBERNATE



2.3.DESARROLLO PASO A PASO



1. Determinar el modelo de datos de la aplicación.
   Este ejemplo se trata de una sencilla introducción donde únicamente se dispone de
   dos clases Event y Person tanto en la base de datos del sistema como en el modelo de
   objetos de la aplicación. También se usarán clases auxiliares para la gestión del acceso
   y operaciones con los datos.

   En primer lugar, es necesario crear la Base de datos en MySQL. Su nombre será
   FirstApp pero no se van a crear tablas en la misma ya que se configurará una opción en
   el fichero de configuración de Hibernate (hibernate.cfg.xml) para que genere el
   esquema de la Base de datos al desplegar la aplicación.

   Como se ha comentado, la aplicación se creará a través de Netbeans. Este entorno de
   desarrollo dispone de herramientas para la configuración del acceso a la Base de
   datos.

   En primer lugar es posible que sea necesario configurar el driver de la base de datos
   que se va a utilizar en la aplicación, en este caso MySQL. Para ello es necesario
   seleccionar la opción New Connection… del menú del botón derecho del ratón sobre la
   opción Drivers.




   A continuación se selecciona el fichero .jar que contiene el driver de MySQL y se dejan
   el resto de campos con los valores que aparecen al seleccionarlo. Todo lo relacionado


                                                                                        [8]
HIBERNATE



con la gestión de Drivers NO es propio de Hibernate, se está configurando el entorno
de Netbeans para la utilización de los Asistentes existentes.




Ahora hay que crear la conexión desde la pestaña Services seleccionando la opción
New Connection… del menú del botón derecho del ratón sobre la opción Databases.




                                                                                 [9]
HIBERNATE



   Los datos que se completan son los correspondientes a la conexión con la base de
   datos que se encuentra en el servidor MySQL.




2. Añadir las librerías Java de Hibernate.
   Netbeans dispone de un asistente para la creación de aplicaciones Web donde se
   puede indicar que la aplicación empleará Hibernate. De esta forma, Netbeans realiza
   una serie de acciones de forma automática que ayudarán al desarrollo mediante este
   Framework.

   Se deberá crear un nuevo proyecto web con Netbeans, para ello dirigirse al menú: File
      New Project    Web     Web Application. No se debe olvidar añadir el Framework,
   como muestran las imágenes siguientes.




                                                                                    [10]
HIBERNATE




Al crear el proyecto, Netbeans crea un fichero hibernate.cfg con los valores para conectar
con la Base de datos que se ha establecido al crear el proyecto. Dicho archivo se encuentra
en la carpeta Source Packagesdefault package de la aplicación.



                                                                                       [11]
HIBERNATE



    3. Definir las clases de persistencia.
        El paso siguiente es añadir clases para representar a los elementos de la Base de datos.

        La clase Event (paquete events) es una clase tipo JavaBean sencilla, cuyas propiedades
        coinciden con los campos de la tabla Events que existirá en la Base de datos.

package events;

import java.util.Date;

public class Event {
        private Long id;
        private String title;
        private Date date;

        public Event() {
        }

        public Long getId() {
                return id;
        }

        private void setId(Long id) {
                this.id = id;
        }

        public Date getDate() {
                return date;
        }

        public void setDate(Date date) {
                this.date = date;
        }

        public String getTitle() {
                return title;
        }

        public void setTitle(String title) {
                this.title = title;
        }
}


        La propiedad id representa el identificador único para un evento. Todas las clases de
        persistencia deben tener un identificador si se quiere utilizar el conjunto completo de



                                                                                            [12]
HIBERNATE



        funcionalidades de Hibernate. El constructor sin argumentos también es un requisito
        para todas las clases persistentes.

        Se recomienda en la mayoría de las ocasiones utilizar clases para representar los tipos
        de los atributos en lugar de utilizar tipos básicos, debido a que para aquellos campos
        que se permitan valores nulos en la Base de datos, la representación del valor del
        campo será natural en la representación Java (null), mientras que con tipos básicos
        podría resultar en un error.

        En el paquete events también se introducirá la clase Person, la cual se representará de
        forma similar por el momento:

package events;

public class Person {
        private Long id;
        private int age;
        private String firstname;
        private String lastname;

        public Person() {
        }

        // getters y setters para todas las propiedades
}




    4. Crear los ficheros de mapeo.
    Para cada una de las clases de persistencia tiene que existir un fichero de mapeo que se
    encarga de definir la relación entre las tablas y columnas de éstas en la Base de datos, y las
    clases y sus propiedades en el modelo de objetos.

    En Netbeans existe una utilidad para mapear las clases con las tablas de la Base de datos
    de forma automática. Para ello, seleccionar la opción New         Other      Hibernate
    Hibernate Mapping File




                                                                                              [13]
HIBERNATE




El nombre del fichero (Event.hbm.xml) coincidirá con el nombre de la clase que mapea
y se guardará habitualmente en el mismo paquete donde se encuentra dicha clase.




                                                                                [14]
HIBERNATE



      Solamente queda seleccionar la clase y la tabla a mapear. En este caso no se puede
      especificar ninguna tabla ya que la Base de datos se encuentra vacía.




      Al pulsar Finish se genera un archivo de mapeo, al cual es necesario añadir el nombre
      de la tabla que está mapeando, y completar con los datos del mapeo de las columnas.



<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
        <class name="events.Event" table="EVENTS">
                <id name="id" column="EVENT_ID">
                       <generator class="native"/>
                </id>
                <property name="date" type="timestamp" column="EVENT_DATE"/>
                <property name="title"/>
        </class>
</hibernate-mapping>




                                                                                       [15]
HIBERNATE




Algunos detalles sobre este archivo:

       <class name="events.Event" table="EVENTS">

       Aunque inicialmente el archive se crea con una serie de propiedades para el
       mapeo (dynamic-insert="false" dynamic-update="false" …) se han eliminado
       para simplificar el ejemplo. Realmente las únicas propiedades imprescindibles
       son name (nombre de la clase) y table (nombre de la tabla).



       <id name="id" column="EVENT_ID">

       En primer lugar se declara el identificador. Esta definición se destaca porque se
       identifica con la etiqueta id. La propiedad name representa el nombre del
       atributo en la clase, y la propiedad column el nombre del campo en la tabla.



       <generator class="native"/>

       Dentro del identificador se declara cómo se gestiona la asignación de ésta. En
       este caso se ha elegido el valor native, que delega la gestión de la clave en el
       SGBD utilizado, es decir, que no es necesario preocuparse de la
       gestión/asignación de claves de forma manual. Existen otras posibilidades de
       generadores de clave que se estudiarán más adelante en este documento.



                                                                                    [16]
HIBERNATE




              <property name="date" type="timestamp" column="EVENT_DATE"/>

              La siguiente propiedad en declararse es date. En este caso también name
              representa el nombre del atributo en la clase, y column el nombre del campo
              en la tabla. La propiedad type representa el tipo de datos que se va a utilizar,
              ya que aunque Hibernate es capaz de detectar que este campo se refiere a un
              valor de tipo Date, es necesario especificar si esa fecha se gestionará como
              time, date o timestamp. Esta propiedad type sirve para realizar conversiones
              de tipos si es necesario en la aplicación, de forma que un campo que en la base
              de datos es numérico se trate como String, o Boolean, …



              <property name="title"/>

              Por último se declara el campo title. En este caso solamente se especifica el
              nombre del atributo de la clase porque el nombre coincide con el nombre de la
              columna de la tabla de Base de datos, si no sería necesario especificar el
              nombre de dicha columna.



       El fichero de mapeo para la clase Person quedará de la siguiente forma:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
       <class name="events.Person" table="PERSON">
               <id name="id" column="PERSON_ID">
                       <generator class="native"/>
               </id>
               <property name="age"/>
               <property name="firstname"/>
               <property name="lastname"/>
       </class>
</hibernate-mapping>




                                                                                          [17]
HIBERNATE



   5. Configurar Hibernate.
       Hasta el momento se han creado las clases para representar los objetos de la Base de
       datos y los ficheros de mapeo para las mismas. Para que la aplicación funcione de
       forma correcta, es necesario configurar Hibernate a través de su fichero de
       configuración hibernate.cfg.xml.

       En este fichero se establecerá al menos la conexión con la base de datos, y se
       especificarán cuáles son los ficheros de mapeo que se están empleando en la
       aplicación, es decir, que si un fichero de mapeo no aparece en hibernate.cfg el mapeo
       no funcionará.

       El fichero hibernate.cfg se encuentra en el paquete por defecto de la aplicación. Si se
       abre este fichero con Netbeans, en primer lugar aparece la vista Diseño. Al seleccionar
       la vista XML (esquina superior izquierda de la ventana) aparecerá el código que
       Netbeans introdujo por defecto al crear la aplicación y especificar la conexión a la Base
       de datos que se iba a emplear en la misma:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD
3.0//EN" "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
       <session-factory name="session1">
               <property name="hibernate.dialect">
                       org.hibernate.dialect.MySQLDialect
               </property>
               <property name="hibernate.connection.driver_class">
                       com.mysql.jdbc.Driver
               </property>
               <property name="hibernate.connection.url">
                       jdbc:mysql://localhost:3306/firstapp
               </property>
               <property name="hibernate.connection.username">root</property>
               <property name="hibernate.connection.password">root</property>


               <mapping resource="events/Event.hbm.xml"/>
               <mapping resource="events/Person.hbm.xml"/>
       </session-factory>
</hibernate-configuration>




                                                                                            [18]
HIBERNATE



        <session-factory name="session1">

        Indica el session factory utilizado en la aplicación. Si la aplicación accede a más de una
        Base de datos es necesario declarar más de un session-factory, cada uno de ellos
        identificado por un nombre distinto.



        <property name="hibernate.dialect">

        La propiedad dialect indica la variante de SQL que Hibernate genera a la hora de
        acceder a la Base de datos.



    Además de los datos de la conexión a la Base de datos y los ficheros de mapeo de la
    aplicación (que Netbeans ha introducido de forma automática al crear los propios ficheros
    hbm), en hibernate.cfg deben aparecer propiedades importantes que definen los
    siguientes aspectos:

        current_session_context_class: Hibernate funciona con sesiones para acceder a los
        datos. Es necesario definir una clase de gestión de sesiones para poder realizar
        operaciones con la Base de datos.
        cache.provider_class: especifica el comportamiento de la Caché de 2º nivel.
        show_sql: mostrar en los logs las sentencias SQL que Hibernate lanza cada vez que
        realiza una operación con la Base de datos.
        hbm2ddl.auto: crear el esquema de la Base de datos de forma automática al desplegar
        la aplicación.
    Los valores a añadir a hibernate.cfg para el ejemplo son los siguientes:

<!-- Enable Hibernate's automatic session context management-->
<property name="current_session_context_class">thread</property>
<!-- Disable the second-level cache -->
<property name="cache.provider_class">org.hibernate.cache.NoCacheProvider</property>
<!-- Echo all executed SQL to stdout -->
<property name="show_sql">true</property>
<!-- Drop and re-create the database schema on startup -->
<property name="hbm2ddl.auto">create</property>




                                                                                              [19]
HIBERNATE



6. Crear clases de ayuda.
   Una vez que se ha configurado Hibernate, ya se puede escribir el código Java para el
   acceso a los datos.

   Como se ha comentado anteriormente, Hibernate utiliza el concepto de sesión para
   acceder a los datos, de forma que cualquier operación de consulta o manipulación de
   los datos debe estar enmarcada en una sesión.

   Para que la gestión de sesiones quede aislada del resto de operaciones de acceso a
   datos, y para evitar la duplicidad de código, es habitual generar una clase de ayuda que
   se encarga de la inicialización de sesiones.

   Netbeans permite la generación de esta clase a través del menú New Other
   Hibernate     HibernateUtil. En este caso la clase HibernateUtil se incorporará al
   paquete util.




                                                                                       [20]
HIBERNATE




package util;

import org.hibernate.cfg.Configuration;
import org.hibernate.SessionFactory;

public class HibernateUtil {
        private static final SessionFactory sessionFactory;

        static {
          try {
                   // Create the SessionFactory from hibernate.cfg.xml
                   sessionFactory = new Configuration().configure().buildSessionFactory();
            } catch (Throwable ex) {
                   // Log the exception.
                   System.err.println("Initial SessionFactory creation failed." + ex);
                   throw new ExceptionInInitializerError(ex);
            }
        }

        public static SessionFactory getSessionFactory() {
                return sessionFactory;
        }
}




                                                                                             [21]
HIBERNATE



       Cuando una clase de la aplicación quiera acceder a la sesión actual, simplemente
       invocará al método estático getSessionFactory() (HibernateUtil.getSessionFactory()).



    7. Cargar y guardar objetos.
       Para manipular los datos de la Base de datos se va a crear una clase EventManager en
       el paquete event para el almacenamiento y recuperación de eventos:



public class EventManager {
        public void createAndStoreEvent(String title, Date theDate) {
             //Obtener la sesión actual
             Session session = HibernateUtil.getSessionFactory().getCurrentSession();
             //Comenzar la transacción
             session.beginTransaction();
             //Crear el evento
             Event theEvent = new Event();
             theEvent.setTitle(title);
             theEvent.setDate(theDate);
             //Almacenarlo
             session.save(theEvent);
             //Confirmar transacción
             session.getTransaction().commit();
        }

       public List listEvents() {
           //Obtener la sesión actual
           Session session = HibernateUtil.getSessionFactory().getCurrentSession();
           //Comenzar la transacción
           session.beginTransaction();
           //Obtener la lista de eventos
           List result = session.createQuery("from Event").list();
           //Confirmar transacción
           session.getTransaction().commit();
           return result;
       }
}




                                                                                        [22]
HIBERNATE



Los métodos que se han definido son los siguientes, los cuales se describen para
comprobar la sencillez de las acciones que realizan:

   createAndStoreEvent: crea y almacena un evento realizando los siguientes pasos:
   1. Acceder a la sesión actual: a través del método estático getSessionFactory() de la
       clase HibernateUtil creada anteriormente en el proyecto.
   2. Abrir una transacción: utilizando la sesión actual.
   3. Crear el objeto: de la forma habitual en Java.
   4. Almacenar el objeto: simplemente invocando al método save del interfaz Session
       (sesión actual).
   5. Confirmar la transacción: utilizando también la sesión actual.
   En la siguiente imagen se muestra un esquema del funcionamiento de Hibernate
   basado en sesiones:




   listEvents: obtiene una lista de todos los eventos de la Base de datos realizando los
   siguientes pasos:
   1. Acceder a la sesión actual: a través del método estático getSessionFactory() de la
       clase HibernateUtil creada anteriormente en el proyecto.
   2. Abrir una transacción: utilizando la sesión actual. Las consultas a bases de datos
       también requieren de una transacción en Hibernate.



                                                                                     [23]
HIBERNATE



         3. Obtener el conjunto de resultados: se obtiene una colección (List) de instancias de la
             clase Event cuyos datos coincidirán con los datos de los registros existentes en la
             Base de datos. Existen varias formas de obtener datos de una tabla en Hibernate, en
             este caso se ha utilizado un Query HQL. Posteriormente se tratarán en profundidad
             los aspectos relacionados con los distintos tipos de consultas en Hibernate.
         4. Confirmar la transacción: utilizando también la sesión actual.



   8. Ejecutar la primera versión.
         Para probar lo que se ha implementado hasta el momento se va a crear una sencilla
         aplicación Web.
         Para ello en primer lugar se modificará la página index.jsp del proyecto para que
         funcione como formulario para introducir los datos:

<html>
       <head>
          <meta http-equiv="Content-Type" content="text/html; charset=windows-1252">
          <title>JSP Page</title>
       </head>
       <body>
          <form action="Servlet">
               <table>
                 <tr>
                       <td>title</td><td><input type="text" name="title"></input></td>
                 </tr>
                 <tr>
                       <td>date</td><td><input type="text" name="date"></input></td>
                 </tr>
                 <tr>
                       <td><input type="submit"/></td>
                 </tr>
               </table>
          </form>
       </body>
</html>




                                                                                              [24]
HIBERNATE



A continuación se crea el Servlet que se encargará de la lógica de la aplicación. Para
crear un Servlet Netbeans también dispone de un Asistente a través de la opción New
   Other Web Servlet




Su nombre será Servlet y se almacenará en el paquete servlet. En la siguiente pantalla
se dejan por defecto los parámetros que se añadirán al fichero web.xml.




                                                                                  [25]
HIBERNATE



        Para ejecutar la aplicación simplemente usar la opción Run       Run Main Project (F6).



public class Servlet extends HttpServlet {

        protected void processRequest(HttpServletRequest request,
                  HttpServletResponse response) throws ServletException, IOException {
               response.setContentType("text/html;charset=UTF-8");
               PrintWriter out = response.getWriter();
               try {
                       EventManager mng = new EventManager();

                        //Parsear la fecha
                        Date date = new SimpleDateFormat("dd/MM/yyyy").
                                              parse(request.getParameter("date"));
                        mng.createAndStoreEvent(request.getParameter("title"), date);

                          //Mostrar los datos almacenados
                          this.mostrarTabla(out, mng.listEvents());
                } catch (Exception ex) {
                          out.println(ex);
                } finally {
                          out.close();
                }
        }

        private void mostrarTabla(PrintWriter out, List lista) {
                out.println("<table>");
                Iterator it = lista.iterator();
                //Iterar sobre todos los eventos
                while (it.hasNext()) {
                         Event event = (Event) it.next();
                         out.println("<tr>");
                         out.println("<td>" + event.getTitle() + "</td>");
                         out.println("<td>" + event.getDate() + "</td>");
                         out.println("</tr>");
                }
                out.println("</table>");
        }

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




                                                                                              [26]
HIBERNATE



9. Asociar clases.
   La asociación entre clases es uno de los aspectos más importantes de Hibernate, así
   como la asociación entre tablas es la base del modelo relacional de Bases de datos.

   Este aspecto puede resultar complejo en algunas ocasiones. Posteriormente se
   tratarán en profundidad los aspectos relacionados con los distintos tipos de
   asociaciones en Hibernate.

   En los pasos 3 y 4 se definieron las clases Event y Person a través de código Java y
   ficheros de mapeo. Ahora es necesario modelar la relación que existe entre ambas a
   través de una asociación Hibernate.

   La relación que existe entre ambas tablas es una relación M a M, de forma que a un
   Evento acudirán varias Personas, y una Persona puede acudir a diversos Eventos. A
   nivel de Bases de datos, esta relación dará lugar a una tabla intermedia
   PERSON_EVENT. Esta relación en Hibernate se puede modelar de diversas maneras, y
   además se puede reflejar de distintas formas en las clases implicadas.




   En primer lugar, la relación más sencilla que se puede establecer es la relación
   Unidireccional entre 2 tablas, en este caso entre las tablas Person y Person_Event. Para
   el ejemplo, el tipo de relación escogido es algo complejo, denominado en Hibernate
   como relación con tabla intermedia (join table). En el capítulo 4 se explicarán los tipos
   de relaciones más generales, y la forma de eludir las relaciones complejas, pero es
   bueno presentar en el ejemplo otro tipos de relaciones que pueden encontrarse en
   aplicaciones Hibernate.

   Las relaciones se modelan con colecciones, normalmente conjuntos (Set) de forma que
   se agregan los fragmentos de código que aparecen a continuación. En la clase
   simplemente se crea el atributo de la clase Set y se generan los métodos get/set para
   el mismo.




                                                                                        [27]
HIBERNATE



private Set events = new HashSet();

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


<set name="events" table="PERSON_EVENT">
       <key column="PERSON_ID"/>
       <many-to-many column="EVENT_ID" class="events.Event"/>
</set>


    En Person.hbm.xml se genera una nueva propiedad para la tabla de tipo conjunto. Los
    atributos de esa propiedad son los siguientes:

                name: nombre de la propiedad de la clase a la que hace referencia.
                table: tabla intermedia de la base de datos.
                key: clave de la tabla intermedia (PERSON_EVENT) que aporta la clase actual.
                La propiedad columna es el nombre de la columna de la tabla de Base de
                datos. Es decir, esta etiqueta significa que el nombre del campo que relaciona
                a la tabla que modela la clase Person (PERSON) y a la tabla intermedia
                (PERSON_EVENT) es PERSON_ID, el cual estará relacionado con el campo id de
                la clase Person (en este caso también se denomina PERSON_ID).
                many-to-many: indica para la tabla intermedia (PERSON_EVENT) cuál es la otra
                clase que está implicada en la relación (la clase Event) y cuál es la clave
                foránea que esta clase aporta a la relación.



        Con todo esto únicamente se ha posibilitado que a través de una persona concreta, es
        decir, una instancia de la clase Person, se pueda conocer de forma directa los eventos
        a los cuales está asociada. En Hibernate esto se traduce en acceder simplemente a los
        atributos de dicha clase. Por ejemplo, el método getEvents devuelve un Set con los
        eventos asociados a una persona:




                                                                                          [28]
HIBERNATE



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



       Esta utilidad es suficiente, pero se pueden realizar cosas más avanzadas, como
       manipular objetos persistentes y luego transformarlos en acciones contra la base de
       datos. Por ejemplo, el siguiente método asigna un evento a una persona de forma
       sencilla, sin gestionar claves ni relaciones entre tablas, simplemente a través de la
       relación normal entre conjuntos:

public void addPersonToEvent(Long personId, Long eventId) {
       //Obtener la sesión actual
       Session session = HibernateUtil.getSessionFactory().getCurrentSession();
       //Comenzar la transacción
       session.beginTransaction();
       //Cargar la persona por clave
       Person aPerson = (Person) session.load(Person.class, personId);
       //Cargar el evento por clave
       Event anEvent = (Event) session.load(Event.class, eventId);
       //Agregar el evento a la persona
       aPerson.getEvents().add(anEvent);
       //Confirmar transacción
       session.getTransaction().commit();
}



       La línea aPerson.getEvents().add(anEvent) es donde se crea la relación entre ambos
       elementos, y al realizar la confirmación en la Base de datos se crean los registros
       necesarios para satisfacer dicha relación.

       A continuación se va a modelar la relación inversa. Una relación en Hibernate se puede
       modelar de forma unidireccional o bidireccional. Para el segundo de los casos, se
       establecen en los ficheros de configuración 2 relaciones, por una parte la relación
       directa (que corresponde con la que ya se ha generado en el ejemplo), y por la otra
       parte se modela la relación inversa. Es decir, si en el ejemplo la relación directa servía
       para conocer cuáles eran los eventos a los que estaba asociada una persona, la
       relación inversa proporciona información sobre cuáles son las personas que participan
       en un determinado evento.


                                                                                             [29]
HIBERNATE



         Para ello, en la clase Event se establece también una propiedad de tipo Set que
         almacenará los datos de las personas asociadas a un evento concreto:



private Set participants = new HashSet();


public Set getParticipants() {
         return participants;
}


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


    El mapeo es muy similar al que se estableció para la clase Person, teniendo en cuenta que
    hay que incluir la propiedad inverse (con valor true):

                 name: nombre de la propiedad de la clase a la que hace referencia.
                 table: tabla intermedia de la base de datos.
                 inverse: en toda relación bidireccional uno de los 2 extremos debe ser
                 inverse=true, lo cual es utilizado por Hibernate a la hora de construir las
                 sentencias SQL para interactuar con la Base de datos.
                 key: el nombre del campo que relaciona a la tabla que modela la clase Event
                 (EVENT) y a la tabla intermedia (PERSON_EVENT) es EVENT_ID, el cual estará
                 relacionado con el campo id de la clase Event (EVENT_ID).
                 many-to-many: indica para la tabla intermedia (PERSON_EVENT) cuál es la otra
                 clase que está implicada en la relación (la clase Person) y cuál es la clave
                 foránea que esta clase aporta a la relación (PERSON_ID).



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




                                                                                         [30]
HIBERNATE



        Gracias a esta nueva relación se pueden conocer las personas que pertenecen a un
        determinado evento. La pregunta es, ¿funcionará correctamente un método como el
        siguiente?

public void addPersonToEvent(Long personId, Long eventId) {
        //Obtener la sesión actual
        Session session = HibernateUtil.getSessionFactory().getCurrentSession();
        //Comenzar la transacción
        session.beginTransaction();
        //Cargar la persona por clave
        Person aPerson = (Person) session.load(Person.class, personId);
        //Cargar el evento por clave
        Event anEvent = (Event) session.load(Event.class, eventId);
        //Agregar la persona al evento
        anEvent.getParticipants().add(aPerson);
        //Confirmar transacción
        session.getTransaction().commit();
}



    10. Ejecutar la aplicación.
        Para probar todos los conceptos vistos hasta el momento, se crea un nuevo Servlet de
        la misma forma especificada en el paso 8, donde se realizarán las siguientes pruebas:

                Cargar eventos por clave (emng.loadEvent(new Long(1))), para comprobar si
                existe un evento con identificador igual a 1.
                Almacenar personas (mng.createAndStorePerson(…): almacena una persona
                de prueba.
                Agregar personas a eventos (mng.addPersonToEvent(new Long(1), e.getId())):
                agrega la persona creada anteriormente al evento.
                Listar participantes de un evento (e.getParticipants()): obtiene la lista de
                participantes al evento para mostrar sus nombres y la lista de eventos.




                                                                                          [31]
HIBERNATE



public class ServletP extends HttpServlet {
        protected void processRequest(HttpServletRequest request,
                    HttpServletResponse response) throws ServletException, IOException {
                response.setContentType("text/html;charset=UTF-8");
                PrintWriter out = response.getWriter();
                try {
                         PersonManager mng = new PersonManager();
                         //Comprobar que existe el evento con id=1
                         EventManager emng = new EventManager();
                         Event e = emng.loadEvent(new Long(1));
                         if (e == null) { //No existe el evento
                              out.println("Debe crear un evento");
                         } else {
                              //Almacenar
                              mng.createAndStorePerson(new Integer(30), "José", "Guardiola");


                              //Agregar un evento como prueba (id=1)
                              mng.addPersonToEvent(new Long(1), e.getId());


                              //Refrescar los datos
                              e = emng.loadEvent(new Long(1));


                              //Mostrar los datos almacenados en el evento
                              this.mostrarTabla(out, e.getParticipants());
                         }
                } catch (Exception ex) {
                         out.println(ex);
                } finally {
                         out.close();
                }
        }




                                                                                                [32]
HIBERNATE



         private void mostrarTabla(PrintWriter out, Set lista) {
                 out.println("<table>");
                 Iterator it = lista.iterator();
                 //Iterar sobre todos los eventos
                 while (it.hasNext()) {
                          Person p = (Person) it.next();
                          out.println("<tr>");
                          out.println("<td>" + p.getAge() + "</td>");
                          out.println("<td>" + p.getFirstname() + "</td>");
                          out.println("<td>" + p.getLastname() + "</td>");
                          out.println("<td>" + p.getEvents() + "</td>");
                          out.println("</tr>");
                 }
                 out.println("</table>");
         }
}



Ejemplo:

    1. En primer lugar se crea un evento.




    2. A continuación se pulsa el enlace Prueba relaciones.


    3. Tras la ejecución del código del Servlet se muestra la lista de participantes en el evento
        inicial. Para el ejemplo, la persona que se almacena como prueba estará al menos en el
        evento creado inicialmente.




                                                                                             [33]
HIBERNATE




El código del Servlet resulta sencillo ya que toda la lógica de interacción con Hibernate se
encuentra en las clases PersonManager y EventManager, destacando la forma en que se
han realizado las operaciones basadas en relaciones:

        Agregar personas a eventos (mng.addPersonToEvent(new Long(1), e.getId())): la
        persona se agrega al evento a través del conjunto de eventos en los que participa
        una persona (ver PersonManager).
        Listar participantes de un evento (e.getParticipants()): los participantes a un
        evento se obtienen a través del conjunto de personas que participa en un evento.
        Para ello se carga el evento, se obtienen sus participantes, y para cada uno de ellos
        se muestra su nombre y la lista de eventos en los cuales participa.
El método loadPerson carga una persona a través del valor de su campo clave (id). Para ello
se utiliza el método load del interfaz Session. El procedimiento de recuperación de una
instancia también sigue el esquema de sesiones y transacciones explicado con anterioridad.

El método listPerson devuelve un listado de todas las personas a través de un Criteria. Esta
forma de recuperar datos se explica en el capítulo 5.2 con detenimiento, pero por el
momento destacar que el método setFetchMode posibilita la recuperación de datos
relacionados, es decir, Hibernate por defecto no cargará los datos de los conjuntos que
estén relacionados con una instancia (por ejemplo, los eventos a los que está asociada una
persona) para no sobrecargar innecesariamente al sistema, así que en caso de querer
recuperarlos hay que notificarlo de esta forma, entre otras.




                                                                                         [34]
HIBERNATE



public class EventManager {


       /**
        * Almacenar un evento
        * @param title título
        * @param theDate fecha
        */
       public void createAndStoreEvent(String title, Date theDate) {
             //Obtener la sesión actual
             Session session = HibernateUtil.getSessionFactory().getCurrentSession();
             //Comenzar la transacción
             session.beginTransaction();
             //Crear el evento
             Event theEvent = new Event();
             theEvent.setTitle(title);
             theEvent.setDate(theDate);
             //Almacenarlo
             session.save(theEvent);
             //Confirmar transacción
             session.getTransaction().commit();
       }


       /**
        * Cargar un evento
        * @return evento
        */
       public Event loadEvent(Long eventId) {
             //Obtener la sesión actual
             Session session = HibernateUtil.getSessionFactory().getCurrentSession();
             //Comenzar la transacción
             session.beginTransaction();
             //Cargar el evento por clave



                                                                                        [35]
HIBERNATE



          Event anEvent = (Event) session.createCriteria(Event.class).
              setFetchMode("participants", FetchMode.JOIN).
              setFetchMode("participants.events", FetchMode.JOIN).
              add(Restrictions.eq("id", eventId)).
              uniqueResult();
          //Confirmar transacción
          session.getTransaction().commit();
          return anEvent;
    }


    /**
    * Listar los eventos
    * @return lista de eventos
    */
    public List listEvents() {
          //Obtener la sesión actual
          Session session = HibernateUtil.getSessionFactory().getCurrentSession();
          //Comenzar la transacción
          session.beginTransaction();
          //Obtener la lista de personas
          List result = session.createCriteria(Event.class).
              setFetchMode("participants", FetchMode.JOIN).
              list();
          //Confirmar transacción
          session.getTransaction().commit();
          return result;
    }
}



    El método loadEvent carga un evento a través del valor de su campo clave (id). Para
    ello se utiliza un Criteria al cual se le añade una restricción de igualdad
    (Restrictions.eq) para filtrar por el campo clave (id). Además se utilizan los métodos
    necesarios para que se carguen los participantes de un evento



                                                                                      [36]
HIBERNATE



         (setFetchMode("participants", FetchMode.JOIN)) y para cada uno de dichos
         participantes, que en su propiedad events (ver clase Person) se carguen los datos de
         sus eventos (setFetchMode("participants", FetchMode.JOIN)). De esta forma, para
         cada evento se podrían conocer los datos completos de las personas asociadas (edad,
         nombre, apellidos y eventos a los que se encuentra asociada). El método uniqueResult
         indica que la consulta deberá devolver un único valor, el cual es una instancia de la
         clase solicitada.

         Para estas 2 clases, los ficheros de mapeo quedan configurados según los cambios que
         se han comentado al introducir las relaciones entre ambas. Para ejecutar el proyecto
         simplemente queda modificar la página JSP de inicio, para que incluya la opción
         Prueba relaciones:

<html>
       <head>
          <meta http-equiv="Content-Type" content="text/html; charset=windows-1252">
          <title>JSP Page</title>
       </head>
       <body>
          <form action="Servlet">
               <table>
                 <tr>
                       <td>title</td><td><input type="text" name="title"></input></td>
                 </tr>
                 <tr>
                       <td>date</td><td><input type="text" name="date"></input></td>
                 </tr>
                 <tr>
                       <td><input type="submit"/></td>
                 </tr>
               </table>
          </form>
          <a href="ServletP">Prueba relaciones</a>
       </body>
</html>




                                                                                          [37]
HIBERNATE



   3. FRAMEWORK HIBERNATE


   3.1.INTRODUCCIÓN



En el desarrollo de una aplicación J2EE se trabaja continuamente con objetos. Sin embargo, las
bases de datos relacionales no trabajan con ellos, sino con conjuntos y relaciones entre
conjuntos. Entonces ¿Cómo se almacena un objeto en una base de datos? ¿Y cómo se
mantienen las relaciones cuando se convierte un elemento de una base de datos en un objeto
Java? La causa de esta disparidad es la llamada diferencia Objeto-Relacional.

El problema se agrava cuanto más complejo sea el material a trasladar de un paradigma a otro.
En estos casos se hace necesario un puente entre ambos conceptos. Es lo que se llama un
mapeador objeto-relacional, también conocido por sus siglas en inglés ORM (Object-Relational
Mapping).

Un ORM permite al programador aislarse de los detalles básicos. Basta definir cómo se deben
trasladar los datos entre ambos modelos y el mapeador se encargará de aplicarlo en cada
ocasión.

Hibernate es un potente servicio de consulta y persistencia objeto/relacional con el cual es
posible desarrollar clases persistentes mediante lenguajes orientados a objetos manteniendo
sus características básicas (incluyendo herencia, polimorfismo, colecciones, etc...). Permite
expresar consultas tanto en SQL como en su propia extensión de este lenguaje, denominada
HSQL.

Hibernate es un proyecto de software libre con código abierto, por lo que su desarrollo se
encuentra en continua evolución. La página del proyecto:

http://www.hibernate.org/




                                                                                          [38]
HIBERNATE



   3.2.INSTALACIÓN




IMPORTANTE:
Este apartado sirve como guía de ayuda de instalación manual de Hibernate para su uso
dentro de una aplicación.
No es recomendable realizar la instalación de Hibernate “a mano”. Normalmente, se utilizan
entornos de desarrollo integrados como Netbeans, con los que se puede elegir durante la
creación del proyecto que añada los frameworks deseados, entre ellos Hibernate, de forma
que el entorno los configurará adecuadamente de forma automática.
En caso de que se descargue la última versión, se recomienda seguir la ayuda oficial ya que
estas instrucciones pueden estar obsoletas.



   1. Descargar la distribución de Hibernate Core de:
       https://www.hibernate.org/344.html

   2. Descomprimir el fichero
   3. Copiar los archivos jar necesarios a la carpeta lib de nuestra aplicación:
           a. hibernate3.jar
           b. librequired*.jar
           c. liboptional*.jar
   4. Crear el fichero hibernate.cfg.xml en el paquete por defecto de la aplicación.




   3.3.CONFIGURACIÓN



Hibernate se configura a través hibernate.cfg.xml. En el paso 5 del ejemplo anterior se
explicaron algunos de los elementos de configuración que se pueden encontrar en este
fichero:




                                                                                        [39]
HIBERNATE



<?xml version=”1.0” encoding=”UTF-8”?>
<!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD
3.0//EN" "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
       <hibernate-configuration>
       <session-factory name="session1">
         <property name="hibernate.dialect">
                      org.hibernate.dialect.MySQLDialect
                 </property>
         <property name="hibernate.connection.driver_class">
               com.mysql.jdbc.Driver
                 </property>
         <property name="hibernate.connection.url">
               jdbc:mysql://localhost:3306/firstapp
                 </property>
         <property name="hibernate.connection.username">root</property>
         <property name="hibernate.connection.password">root</property>


         <!-- Enable Hibernate's automatic session context management-->
         <property name="current_session_context_class">thread</property>
         <!-- Disable the second-level cache -->
         <property name="cache.provider_class">
               org.hibernate.cache.NoCacheProvider
                 </property>
         <!-- Echo all executed SQL to stdout -->
         <property name="show_sql">true</property>
         <!-- Drop and re-create the database schema on startup -->
         <property name="hbm2ddl.auto">create</property>


         <mapping resource="events/Event.hbm.xml"/>
         <mapping resource="events/Person.hbm.xml"/>
       </session-factory>
</hibernate-configuration>




                                                                               [40]
HIBERNATE



Este archivo es leído por el framework cuando arranca y contiene los siguientes elementos:

       Sesiones: session factory utilizados en la aplicación. Si la aplicación accede a más de
       una Base de datos es necesario declarar más de un session-factory, cada uno de ellos
       identificado por un nombre distinto.


       Propiedades: dentro de cada sesión se declaran una serie propiedades para la
       conexión y configuración del acceso a la Base de datos:


               Datos de la conexión: datos para conectar con la Base de datos.


     hibernate.connection.driver_class         Driver JDBC de la Base de datos
     hibernate.connection.url                  URL de conexión a la Base de datos
     hibernate.connection.username             Usuario
     hibernate.connection.password             Clave
     hibernate.connection.pool_size            Máximo número de conexiones del pool


               Propiedades de configuración: parámetros de configuración generales.


     hibernate.max_fetch_depth            Profundidad máxima de
                                          joins para relaciones simples
     hibernate.default_batch_fetch_size   Tamaño por defecto para el
                                          fetching de asociaciones
     hibernate.default_entity_mode        Modo por defecto para la        dynamic-map
                                          representación de entidades     dom4j
                                                                          pojo
     hibernate.order_updates              Ordenar las actualizaciones     true
                                          por clave primaria              false
     hibernate.generate_statistics        Generar estadísticas de         true
                                          rendimiento                     false
     hibernate.use_identifier_rollback    Resetea el identificador        true
                                          asociado en caso de             false
                                          eliminación
     hibernate.use_sql_comments           Genera comentarios en las       true
                                          sentencias SQL                  false




                                                                                             [41]
HIBERNATE



               Propiedades de conexión: otras propiedades de la conexión.


hibernate.jdbc.fetch_size                 Tamaño de búsqueda


hibernate.jdbc.batch_size                 Actualización batch de JDBC2


                                          Utilizar el rowcount que devuelve true
hibernate.jdbc.batch_versioned_data
                                          executeBatch()                    false

                                          Seleccionar un
hibernate.jdbc.factory_class
                                          org.hibernate.jdbc.Batcher propio


                                          Uso de resultsets scrollables de    true
hibernate.jdbc.use_scrollable_resultset
                                          JDBC2                               false


                                          Uso de streams para la escritura    true
hibernate.jdbc.use_streams_for_binary
                                          de tipos de datos serializables     false


                                          Uso de getGeneratedKeys() de        true
hibernate.jdbc.use_get_generated_keys
                                          JDBC3                               false

                                          Uso de un ConnectionProvider
hibernate.connection.provider_class
                                          propio

                                                                              true
hibernate.connection.autocommit           Habilita el Autocommit
                                                                              false

                                                                           auto
                                          Modo de Liberación de conexiones on_close
hibernate.connection.release_mode
                                          JDBC                             after_transaction
                                                                           after_statement

                                          Propiedad específica de JDBC para
hibernate.connection.<propertyName>
                                          la conexión

                                          Propiedad específica de JNDI para
hibernate.jndi.<propertyName>
                                          la conexión

                                          Nivel de aislamiento de
hibernate.connection.isolation
                                          transacciones




                                                                                         [42]
HIBERNATE



       Propiedades de caché: gestión de la caché de segundo nivel.


                                           Nombre de CacheProvider
hibernate.cache.provider_class
                                           propio.

                                           Optimizar la operación de la
                                                                               true
hibernate.cache.use_minimal_puts           caché al mínimo número de
                                                                               false
                                           escrituras.

                                                                               true
hibernate.cache.use_query_cache            Habilitar la cache de consultas
                                                                               false

                                           Deshabilitar completamente la       true
hibernate.cache.use_second_level_cache
                                           cache                               false

                                           Nombre de un interfaz
hibernate.cache.query_cache_factory
                                           QueryCache propio

                                           Prefijo de los nombres
hibernate.cache.region_prefix
                                           regionales de la caché

                                                                               true
hibernate.cache.use_structured_entries Usar entradas de cache legibles
                                                                               false


       Propiedades de transacciones: gestión de transacciones.


                                                 Nombre de la factoría de
hibernate.transaction.factory_class
                                                 transacciones

                                                 Nombre para obtener la
jta.UserTransaction
                                                 transacción JTA

                                                 Nombre del
hibernate.transaction.manager_lookup_class
                                                 TransactionManagerLookup


                                                 La sesión se lanza antes de           true
hibernate.transaction.flush_before_completion
                                                 concluir la transacción               false

                                                 Cierra la sesión tras concluir la true
hibernate.transaction.auto_close_session
                                                 transacción                       false




                                                                                               [43]
HIBERNATE



        Otras propiedades.



                                        Estrategia para          jta
                                        obtener la sesión        thread
hibernate.current_session_context_class
                                        actual                   managed
                                                                 custom Class

                                                                 org.hibernate.hql.ast.
                                                                 ASTQueryTranslatorFactory
                                           Implementación del
hibernate.query.factory_class
                                           HQL Parser
                                                                 org.hibernate.hql.classic.
                                                                 ClassicQueryTranslatorFactory

                                           Mapeo a consultas
hibernate.query.substitutions
                                           SQL

                                                              validate
                                           Genera el esquema update
hibernate.hbm2ddl.auto                     automáticamente al
                                                              create
                                           crear la Sesión
                                                              create-drop

                                           Utilización de CGLIB true
hibernate.cglib.use_reflection_optimizer
                                           en lugar de reflexión false



        Mapeos: ficheros de mapeo de clases (hbm.xml) que se utilizan en la aplicación.




    3.3.1. MAPEOS



Los ficheros de mapeo que se utilizan en la aplicación se definen en hibernate.cfg, indicando la
ruta donde se encuentran los mismos. Cada uno de estos ficheros con extensión hbm.xml
mapean una clase de la aplicación con una de las tablas de la Base de datos especificada en la
conexión, y contienen los detalles de dicho mapeo.




                                                                                            [44]
HIBERNATE




Los ficheros de mapeo normalmente incluyen el nombre de la tabla y clase relacionadas, y el
detalle del mapeo entre columnas de la tabla y propiedades de la clase, como puede
observarse en la ilustración anterior. Un fichero de mapeo puede contener varias clases
mapeadas, aunque habitualmente se realiza con una sola clase (cuyo nombre debería coincidir
con el nombre del fichero de mapeo).

Los elementos básicos de un fichero de mapeo aparecen a continuación. Se marcarán en
negrita aquellos elementos importantes para su utilización:

   1. hibernate-mapping: datos generales del mapeo.


<hibernate-mapping
       schema="schemaName" (a)
       catalog="catalogName" (b)
       default-cascade="cascade_style" (c)
       default-access="field|property|ClassName" (d)
       default-lazy="true|false" (e)
       auto-import="true|false" (f)
       package="package.name" (g)
/>


           a. schema (opcional): nombre del esquema de bases de datos.
           b. catalog (opcional): nombre del catálogo de la base de datos.
           c. default-cascade (opcional – none por defecto): estilo de cascada por defecto.


                                                                                         [45]
HIBERNATE



             d. default-access (opcional – property por defecto): estrategia de acceso a las
                  propiedades.
             e. default-lazy (opcional – true por defecto): valor por defecto del atributo lazy
                  de los mapeos de clases y colecciones.
             f.   auto-import (opcional – true por defecto): permite usar nombres de clases sin
                  calificar en el lenguaje SQL. Si hay dos clases con el mismo nombre sin calificar,
                  esta propiedad tiene que tener el valor false.
             g. package (opcional): prefijo de paquete para los nombres de clases sin cualificar.


     2. class: datos de la clase persistente y su relación con la tabla de la base de datos.
<class
         name="ClassName" (a)
         table="tableName" (b)
         discriminator-value="discriminator_value" (c)
         mutable="true|false" (d)
         schema="owner" (e)
         catalog="catalog" (f)
         proxy="ProxyInterface" (g)
         dynamic-update="true|false" (h)
         dynamic-insert="true|false" (i)
         select-before-update="true|false" (j)
         polymorphism="implicit|explicit" (k)
         where="arbitrary sql where condition" (l)
         persister="PersisterClass" (m)
         batch-size="N" (n)
         optimistic-lock="none|version|dirty|all" (o)
         lazy="true|false" (p)
         entity-name="EntityName" (q)
         check="arbitrary sql check condition" (r)
         rowid="rowid" (s)
         subselect="SQL expression" (t)
         abstract="true|false" (u)
         node="element-name"
/>




                                                                                                [46]
HIBERNATE



a. name (opcional): nombre completo de la clase o interfaz Java. También se
     pueden hacer persistentes clases estáticas internas.
b. table (opcional – por defecto el nombre de la clase sin cualificar): nombre de
     la tabla de la base de datos.
c. discriminator-value (opcional – por defecto el nombre de la clase): distingue
     subclases individuales, se usa para comportamiento polimórfico.
d. mutable (opcional – true por defecto): especifica si las instancias son mutables
     o no. Las clases inmutables no se pueden modificar ni eliminar.
e. schema (opcional): sobreescribe el nombre de esquema especificado por
     <hibernate-mapping>.
f.   catalog (opcional): sobreescribe el nombre de catálogo especificado por
     <hibernate-mapping>.
g. proxy (opcional): interfaz de proxy para la incialización perezosa.
h. dynamic-update (opcional – false por defecto): la sentencia SQL UPDATE se
     genera en tiempo de ejecución y solamente contiene las columnas cuyos
     valores hayan cambiado.
i.   dynamic-insert (opcional – false por defecto): la sentencia SQL INSERT se
     genera en tiempo de ejecución y solamente contiene las columnas cuyos
     valores son distintos a null.
j.   select-before-update (opcional – false por defecto): se produce una sentencia
     SELECT antes de actualizar para comprobar si un objeto ha sido modificado. Si
     no no se produce dicha actualización.
k. polymorphism (opcional – implicit por defecto): determina si se utiliza
     polimorfismo implícito o explícito a la hora de recuperar objetos en las
     consultas.
l.   where (opcional): condición WHERE a utilizar cuando se recuperan objetos de
     esta clase.
m. persister (opcional): especifica un ClassPersister propio, permitiendo la
     redefinición de la estrategia de almacenamiento persistente.
n. batch-size (opcional – 1 por defecto): tamaño batch para la búsqueda de
     instancias de esta clase por campo clave.




                                                                               [47]
HIBERNATE



              o. optimistic-lock (opcional – version por defecto): determina la estrategia de
                   bloqueo optimista.
              p. lazy (opcional): búsqueda perezosa.
              q. entity-name (opcional – por defecto el nombre de la clase): Hibernate3
                   permite mapear una misma clase distintas veces (con distintas tablas), y este
                   nombre será el utilizado.
              r.   check (opcional): expression SQL para generar una comprobación en la
                   generación automática de esquemas.
              s. rowid (opcional): utilización de ROWID.
              t.   subselect (opcional): mapea una entidad immutable de solo lectura con una
                   subconsulta de la base de datos, por ejemplo para usar vistas en lugar de
                   tablas.
              u. abstract (opcional): marca superclases abstractas en jerarquías con <union-
                   subclass>.
      3. id: dentro de la etiqueta class, se debe mapear la clave primaria de la tabla.



<id
         name="propertyName" (a)
         type="typename" (b)
         column="column_name" (c)
         unsaved-value="null|any|none|undefined|id_value" (d)
         access="field|property|ClassName"> (e)
         node="element-name|@attribute-name|element/@attribute|."
         <generator class="generatorClass"/>
</id>



              a. name (opcional): nombre de la propiedad.
              b. type (opcional): indica el tipo.
              c. column (opcional –nombre de la propiedad por defecto): nombre de la
                   columna.




                                                                                            [48]
HIBERNATE



           d. unsaved-value (opcional): valor del identificador que indica que la instancia es
               nueva, para distinguir de instancias guardadas o cargadas en sesiones
               anteriores. Casi nunca se utiliza en Hibernate 3.
           e. access (opcional – property por defecto): estrategia de acceso al valor de la
               propiedad.
   4. generator: dentro del id, es necesario definir un generador de identificadores únicos
       para la clase.



<generator class="org.hibernate.id.TableHiLoGenerator">
       <param name="table">uid_table</param>
       <param name="column">next_hi_value_column</param>
</generator>



           a. class:     nombre        de   la   clase     que     implementa   el    interfaz
               org.hibernate.id.IdentifierGenerator, a la cual se pueden pasar parámetros a
               través de los elementos <param>. Asimismo, existe una serie de clases
               predefinidas:
                    i. increment: identificadores únicos siempre que no existan otros
                        procesos insertando en la tabla.
                    ii. identity: columna de tipo identity (autonumérica) para aquellos
                        sistemas que la soportan.
                   iii. sequence: asignación basada en secuencia para aquellos sistemas que
                        la soportan.
                   iv. hilo: genera identificadores con un algoritmo hi/lo dado un nombre de
                        tabla y de columna.
                    v. seqhilo: genera identificadores con un algoritmo hi/lo dado un nombre
                        de secuencia.
                   vi. uuid: genera claves de tipo uuid de tamaño 32.
                   vii. guid: usa una cadena guid generada por la base de datos para aquellos
                        sistemas que la soportan.




                                                                                          [49]
HIBERNATE



                viii. native: selecciona identity, sequence o hilo dependiendo de la base de
                     datos en uso.
                 ix. assigned: asignado por la aplicación. Es la opción por defecto si no se
                     incluye generator.
                  x. select: asignación por trigger.
                 xi. foreign: usa el identificador de otro objeto asociado, normalmente a
                     través de un <one-to-one>.
                 xii. sequence-identity: usa una secuencia y el método getGeneratedKeys
                     de JDBC3 para la generación.


   5. composite-id: utilizado en el caso que la clave primaria esté compuesta por más de
      una columna.
<composite-id
      name="propertyName" (a)
      class="ClassName" (b)
      mapped="true|false" (c)
      access="field|property|ClassName"> (d)
      node="element-name|."
      <key-property name="propertyName" type="typename" column="column_name"/>
(e)
      <key-many-to-one              name="propertyName         class="ClassName"
column="column_name"/> (f)
      ......
</composite-id>


          a. name (opcional): nombre de la propiedad.
          b. class (opcional): la forma de implementar una clave compuesta en Hibernate
              es a través de una clase. Esta propiedad indica el nombre de dicha clase, que
              contendrá atributos para cada una de las columnas que componen la clave.
          c. mapped (opcional – false por defecto): utilización de un identificador
              compuesto mapeado.
          d. access (opcional – property por defecto): estrategia de acceso al valor de la
              propiedad.




                                                                                         [50]
HIBERNATE



          e. key-property: dentro de la etiqueta composite-id, indica cada uno de los campos
               que forman la clave y que no corresponden a claves foráneas de otras tablas:
                    i. name: nombre de la propiedad (de la clase que implementa el
                       identificador).
                   ii. type (opcional): tipo Hibernate de la propiedad.
                  iii. column (opcional – nombre de la propiedad por defecto): nombre de
                       la columna.
          f.   key-many-to-one: dentro de la etiqueta composite-id, indica cada uno de los
               campos que forman la clave y que corresponden a claves foráneas de otras tablas:
                    i. name: nombre de la propiedad (de la clase que implementa el identificador).
                   ii. class: nombre de la clase relacionada a través de la clave foránea.
                  iii. column (opcional – nombre de la propiedad por defecto): nombre de
                       la columna.
   6. property: declaración de propiedades de la clase.


<property
       name="propertyName" (a)
       column="column_name" (b)
       type="typename" (c)
       update="true|false" (d)
       insert="true|false" (e)
       formula="arbitrary SQL expression" (f)
       access="field|property|ClassName" (g)
       lazy="true|false" (h)
       unique="true|false" (i)
       not-null="true|false" (j)
       optimistic-lock="true|false" (k)
       generated="never|insert|always" (l)
       node="element-name|@attribute-name|element/@attribute|."
       index="index_name"
       unique_key="unique_key_id"
       length="L"
       precision="P"
       scale="S"
/>



                                                                                               [51]
HIBERNATE



      a. name: nombre de la propiedad (primera letra siempre en minuscule).
      b. column (opcional – nombre de la propiedad por defecto): nombre de la
           columna de base de datos mapeada. También puede ser especificado a través
           de etiquetas <column>.
      c. type (opcional): indica el tipo Hibernate, que puede tratarse de uno de los
           siguientes, aunque en caso de no especificar Hibernate lo asignará
           automáticamente en función del tipo de la columna de base de datos:
               i. Tipo básico Hibernate (integer, string, character, date, …).
               ii. Clase Java o tipo básico (int, float, java.util.Date, …).
              iii. Clase Java serializable.
              iv. Clase propia.
      d. update (opcional – true por defecto): las columnas mapeadas deben incluirse
           en las sentencias UPDATE.
      e. insert (opcional – true por defecto): las columnas mapeadas deben incluirse en
           las sentencias INSERT.
      f.   formula (opcional): expresión SQL que define el valor de una propiedad
           calculada. Las propiedades calculadas no se mapean a ninguna columna.
      g. access (opcional – property por defecto): estrategia utilizada para acceder a la
           propiedad.
      h. lazy (opcional – false por defecto): indica si esta propiedad debe ser buscada
           de forma perezosa cuando la instancia se accede por vez primera.
      i.   unique (opcional): restricción unique para esta columna.
      j.   not-null (opcional): restricción not-null para esta columna.
      k. optimistic-lock (opcional – true por defecto): las actualizaciones de esta
           propiedad requieren la adquisición del bloqueo optimista.
      l.   generated (opcional – never por defecto): esta propiedad es generada por la
           base de datos.
7. many-to-one




                                                                                     [52]
HIBERNATE



<many-to-one
      name="propertyName" (a)
      column="column_name" (b)
      class="ClassName" (c)
      cascade="cascade_style" (d)
      fetch="join|select" (e)
      update="true|false" (f)
      insert="true|false" (g)
      property-ref="propertyNameFromAssociatedClass" (h)
      access="field|property|ClassName" (i)
      unique="true|false" (j)
      not-null="true|false" (k)
      optimistic-lock="true|false" (l)
      lazy="proxy|no-proxy|false" (m)
      not-found="ignore|exception" (n)
      entity-name="EntityName" (o)
      formula="arbitrary SQL expression" (p)
      node="element-name|@attribute-name|element/@attribute|."
      embed-xml="true|false"
      index="index_name"
      unique_key="unique_key_id"
      foreign-key="foreign_key_name"
/>


          a. name: nombre de la propiedad.
          b. column (opcional): nombre de la columna de clave foránea. También puede
               ser especificado a través de etiquetas <column>.
          c. class (opcional): nombre de la clase asociada.
          d. cascade (opcional): operaciones que deben ejecutarse en cascada desde el
               padre al objeto asociado.
          e. fetch (opcional – select por defecto): elige entre búsqueda mediante outer-
               join o select secuencial.
          f.   update (opcional – true por defecto): las columnas mapeadas deben incluirse
               en las sentencias UPDATE.
          g. insert (opcional – true por defecto): las columnas mapeadas deben incluirse en
               las sentencias INSERT.


                                                                                       [53]
HIBERNATE



          h. property-ref (opcional): nombre de la propiedad de la clase asociada relacionada
               con esta foreign key. Si no se especifica se utiliza la clave de la clase asociada.
          i.   access (opcional – property por defecto): estrategia utilizada para acceder a la
               propiedad.
          j.   unique (opcional): restricción unique para la clave foránea.
          k. not-null (opcional): restricción not-null para la clave foránea.
          l.   optimistic-lock (opcional – true por defecto): las actualizaciones de esta
               propiedad requieren la adquisición del bloqueo optimista.
          m. lazy (optional – proxy por defecto): indica si esta propiedad debe ser buscada
               de forma perezosa cuando la instancia se accede por vez primera.
          n. not-found (opcional – exception por defecto): cómo se tratan las claves
               foráneas que referencian a filas inexistentes.
          o. entity-name (opcional): nombre de entidad de la clase asociada.
          p. formula (opcional): expresión SQL que define el valor de una propiedad calculada.


   8. one-to-one
<one-to-one
       name="propertyName" (a)
       class="ClassName" (b)
       cascade="cascade_style" (c)
       constrained="true|false" (d)
       fetch="join|select" (e)
       property-ref="propertyNameFromAssociatedClass" (f)
       access="field|property|ClassName" (g)
       formula="any SQL expression" (h)
       lazy="proxy|no-proxy|false" (i)
       entity-name="EntityName" (j)
       node="element-name|@attribute-name|element/@attribute|."
       embed-xml="true|false"
       foreign-key="foreign_key_name"
/>


          a. name: nombre de la propiedad.
          b. class (opcional): nombre de la clase asociada.



                                                                                                     [54]
HIBERNATE



       c. cascade (opcional): operaciones que deben ejecutarse en cascada desde el
            padre al objeto asociado.
       d. constrained (opcional): una clave foránea de la clave primaria de la tabla
            mapeada referencia a la tabla de la clase asociada.
       e. fetch (opcional – select por defecto): elige entre búsqueda mediante outer-
            join o select secuencial.
       f.   property-ref (opcional): nombre de la propiedad de la clase asociada relacionada
            con esta foreign key. Si no se especifica se utiliza la clave de la clase asociada.
       g. access (opcional – property por defecto): estrategia utilizada para acceder a la
            propiedad.
       h. formula (opcional): expresión SQL que define el valor de una propiedad calculada.
       i.   lazy (optional – proxy por defecto): indica si esta propiedad debe ser buscada
            de forma perezosa cuando la instancia se accede por vez primera.
       j.   entity-name (opcional): nombre de entidad de la clase asociada.


9. set: las relaciones inversas normalmente se modelan a través de un conjunto (set), pero
   existen otros elementos que se pueden usar como list, map, bag, array o primitive-array.




                                                                                                  [55]
HIBERNATE



<set
         name="propertyName" (a)
         table="table_name" (b)
         schema="schema_name" (c)
         lazy="true|extra|false" (d)
         inverse="true|false" (e)
         cascade="all|none|save-update|delete|all-delete-orphan|delete-orphan" (f)
         sort="unsorted|natural|comparatorClass" (g)
         order-by="column_name asc|desc" (h)
         where="arbitrary sql where condition" (i)
         fetch="join|select|subselect" (j)
         batch-size="N" (k)
         access="field|property|ClassName" (l)
         optimistic-lock="true|false" (m)
         mutable="true|false" (n)
         node="element-name|."
         embed-xml="true|false" >
         <key .... /> (o)
         <map-key .... />
         <element .... />
</map>


            a. name: nombre de la propiedad.
            b. table (opcional – nombre de la propiedad por defecto): nombre de la tabla de
                 la colección (no se usa para one-to-many).
            c. schema (opcional): nombre del esquema para sobreescribir el esquema
                 definido en el elemento raíz.
            d. lazy (opcional – true por defecto).
            e. inverse (opcional – false por defecto): indica el lado inverso en una asociación
                 bidireccional.
            f.   cascade (opcional - none por defecto): permite operaciones en cascada sobre
                 los elementos hijos.
            g. sort (opcional): especifica una colección ordenada mediante orden natural o
                 especificando una clase comparadora.




                                                                                           [56]
HIBERNATE



           h. order-by (opcional): solo en JDK 1.4, especifica un nombre de columna que
                define el orden de iteración.
           i.   where (opcional): condición WHERE a utilizar cuando se recuperan o eliminan
                objetos de la colección.
           j.   fetch (opcional – select por defecto): elige entre búsqueda mediante outer-
                join o select secuencial.
           k. batch-size (opcional – 1 por defecto): tamaño batch para la búsqueda de
                instancias de esta clase por campo clave.
           l.   access (opcional – property por defecto): estrategia utilizada para acceder a la
                propiedad.
           m. optimistic-lock (opcional – true por defecto): las actualizaciones del estado de
                la colección requieren la adquisición del bloqueo optimista.
           n. mutable (opcional – true por defecto): los elementos de la colección nunca
                cambian.
           o. key: dentro de la etiqueta set indica la clave foránea de la colección:


<key
       column="columnname" (i)
       on-delete="noaction|cascade" (ii)
       property-ref="propertyName" (iii)
       not-null="true|false" (iv)
       update="true|false" (v)
       unique="true|false" (vi)
/>


                     i. column (opcional): nombre de la columna que actúa como clave foránea.
                        También puede especificarse a través de elementos <column>.
                    ii. on-delete (opcional – noaction por defecto): la clave foránea tiene
                        activado el borrado en cascada en la base de datos.
                   iii. property-ref (opcional): la clave foránea se refiere a columnas que no
                        son la clave primaria de la tabla original.
                   iv. not-null (opcional): las claves foráneas no se pueden establecer como
                        null.


                                                                                            [57]
HIBERNATE



                      v. update (opcional): las claves foráneas no se pueden actualizar.
                     vi. unique (opcional): la clave foránea debería tener una restricción
                          unique.


             p. one-to-many: indica


<one-to-many
       class="ClassName" (i)
       not-found="ignore|exception" (ii)
       entity-name="EntityName" (iii)
       node="element-name"
       embed-xml="true|false"
/>


                      i. class: nombre de la clase asociada.
                      ii. not-found (opcional – exception por defecto): cómo se tratan las
                          claves foráneas que referencian a filas inexistentes.
                     iii. entity-name (opcional): nombre de entidad de la clase asociada.




    3.4.EL INTERFAZ SESSION



El interfaz Session es la principal vía de interacción entre la aplicación Java e Hibernate. Representa
a la sesión actual, donde se producen transacciones para la interacción con la Base de datos,
efectuando operaciones de lectura, creación, modificación y eliminación de instancias de clases
mapeadas. Las instancias de tales clases se pueden encontrar en tres estados posibles:

        transient: no es persistente, no está asociada a ninguna sesión. Se pueden convertir en
        persistent invocando a los métodos save, persist o saveOrUpdate. Se encuentra en la
        aplicación pero no en la Base de datos.
        persistent: asociado a una única sesión. Se encuentra en la aplicación y en la Base de
        datos.




                                                                                                   [58]
HIBERNATE



        detached: persistente previamente, no asociado con ninguna sesión. Se encuentra en
        la Base de datos, pero no se ha recuperado desde la aplicación.



En la siguiente ilustración aparecen estos estados, y cuáles son los métodos que provocan la
transición de uno a otro.




Para poder operar con una sesión es necesario obtener una instancia de la misma y comenzar
una transacción. Cualquier operación sobre dicha instancia debe contenerse dentro de una
transacción.

Si se produce una excepción dentro de la transacción, ésta debe ser cancelada (rollback), si no
hay que confirmarla para hacer persistentes los cambios (commit):




                                                                                           [59]
HIBERNATE



//Obtener la sesión actual
Session session = HibernateUtil.getSessionFactory().getCurrentSession();

try{
          //Comenzar la transacción
          session.beginTransaction();
          //Operaciones con session
          …
}catch (Exception ex){
          //Deshacer transacción
          session.getTransaction().rollback();
}finally{
          //Confirmar transacción
          session.getTransaction().commit();
}


Los métodos que se invocan sobre la instancia de Session producen operaciones sobre la Base
de datos a través de sentencias SQL, generadas en el dialecto concreto configurado en
hibernate.cfg. De esta forma, las siguientes sentencias se producen para los métodos
enumerados anteriormente:

        INSERT: save, persist, saveOrUpdate, replicate.
        UPDATE: update, merge, saveOrUpdate, replicate.
        DELETE: delete.



A continuación se exponen algunos métodos de la clase Session utilizados habitualmente. Para
mayor información se puede acceder a la API de Hibernate:

http://www.hibernate.org/hib_docs/v3/api/




                                                                                        [60]
Manual hibernate v2
Manual hibernate v2
Manual hibernate v2
Manual hibernate v2
Manual hibernate v2
Manual hibernate v2
Manual hibernate v2
Manual hibernate v2
Manual hibernate v2
Manual hibernate v2
Manual hibernate v2
Manual hibernate v2
Manual hibernate v2
Manual hibernate v2
Manual hibernate v2
Manual hibernate v2
Manual hibernate v2
Manual hibernate v2
Manual hibernate v2
Manual hibernate v2
Manual hibernate v2
Manual hibernate v2
Manual hibernate v2
Manual hibernate v2
Manual hibernate v2
Manual hibernate v2
Manual hibernate v2
Manual hibernate v2
Manual hibernate v2
Manual hibernate v2

Weitere ähnliche Inhalte

Was ist angesagt?

Apache Commons Pool and DBCP - Version 2 Update
Apache Commons Pool and DBCP - Version 2 UpdateApache Commons Pool and DBCP - Version 2 Update
Apache Commons Pool and DBCP - Version 2 UpdatePhil Steitz
 
Unpack mechanism of the msgpack-c
Unpack mechanism of the msgpack-cUnpack mechanism of the msgpack-c
Unpack mechanism of the msgpack-cTakatoshi Kondo
 
まだ DOM 操作で消耗してるの?
まだ DOM 操作で消耗してるの?まだ DOM 操作で消耗してるの?
まだ DOM 操作で消耗してるの?Yuki Ishikawa
 
Hibernate Presentation
Hibernate  PresentationHibernate  Presentation
Hibernate Presentationguest11106b
 
java 8 new features
java 8 new features java 8 new features
java 8 new features Rohit Verma
 
Introduction to Linked Data 1/5
Introduction to Linked Data 1/5Introduction to Linked Data 1/5
Introduction to Linked Data 1/5Juan Sequeda
 
Migrating from Struts 1 to Struts 2
Migrating from Struts 1 to Struts 2Migrating from Struts 1 to Struts 2
Migrating from Struts 1 to Struts 2Matt Raible
 
Ch12 Spring 起步走
Ch12 Spring 起步走Ch12 Spring 起步走
Ch12 Spring 起步走Justin Lin
 
Spring framework Controllers and Annotations
Spring framework   Controllers and AnnotationsSpring framework   Controllers and Annotations
Spring framework Controllers and AnnotationsAnuj Singh Rajput
 

Was ist angesagt? (14)

Apache Commons Pool and DBCP - Version 2 Update
Apache Commons Pool and DBCP - Version 2 UpdateApache Commons Pool and DBCP - Version 2 Update
Apache Commons Pool and DBCP - Version 2 Update
 
Complete Java Course
Complete Java CourseComplete Java Course
Complete Java Course
 
Unpack mechanism of the msgpack-c
Unpack mechanism of the msgpack-cUnpack mechanism of the msgpack-c
Unpack mechanism of the msgpack-c
 
まだ DOM 操作で消耗してるの?
まだ DOM 操作で消耗してるの?まだ DOM 操作で消耗してるの?
まだ DOM 操作で消耗してるの?
 
Spring ioc
Spring iocSpring ioc
Spring ioc
 
Hibernate Presentation
Hibernate  PresentationHibernate  Presentation
Hibernate Presentation
 
java 8 new features
java 8 new features java 8 new features
java 8 new features
 
Java servlets and CGI
Java servlets and CGIJava servlets and CGI
Java servlets and CGI
 
Introduction to Linked Data 1/5
Introduction to Linked Data 1/5Introduction to Linked Data 1/5
Introduction to Linked Data 1/5
 
Java persistence api 2.1
Java persistence api 2.1Java persistence api 2.1
Java persistence api 2.1
 
Migrating from Struts 1 to Struts 2
Migrating from Struts 1 to Struts 2Migrating from Struts 1 to Struts 2
Migrating from Struts 1 to Struts 2
 
Ch12 Spring 起步走
Ch12 Spring 起步走Ch12 Spring 起步走
Ch12 Spring 起步走
 
Jsp ppt
Jsp pptJsp ppt
Jsp ppt
 
Spring framework Controllers and Annotations
Spring framework   Controllers and AnnotationsSpring framework   Controllers and Annotations
Spring framework Controllers and Annotations
 

Ähnlich wie Manual hibernate v2 (20)

Motor de persistencia nhibernate
Motor de persistencia nhibernateMotor de persistencia nhibernate
Motor de persistencia nhibernate
 
Sesion03 apuntes
Sesion03 apuntesSesion03 apuntes
Sesion03 apuntes
 
Java
JavaJava
Java
 
Tema 5
Tema 5Tema 5
Tema 5
 
Java con base de datos
Java con base  de datosJava con base  de datos
Java con base de datos
 
Manual hibernate
Manual hibernateManual hibernate
Manual hibernate
 
Manual Basico De Struts
Manual Basico De StrutsManual Basico De Struts
Manual Basico De Struts
 
Capitulo 8 soporte spring jdbc 0
Capitulo 8   soporte spring jdbc 0Capitulo 8   soporte spring jdbc 0
Capitulo 8 soporte spring jdbc 0
 
Hibernate - Introducción
Hibernate - IntroducciónHibernate - Introducción
Hibernate - Introducción
 
Bases de datos con java
Bases de datos con javaBases de datos con java
Bases de datos con java
 
ejemplo de diseño
ejemplo de diseñoejemplo de diseño
ejemplo de diseño
 
Base de datos objeto
Base de datos objetoBase de datos objeto
Base de datos objeto
 
Jdbc
JdbcJdbc
Jdbc
 
Jdbc
JdbcJdbc
Jdbc
 
Persistencia de objetos con Hibernate
Persistencia de objetos con HibernatePersistencia de objetos con Hibernate
Persistencia de objetos con Hibernate
 
POO
POOPOO
POO
 
Aplicación abc. asp net mvc 3
Aplicación abc. asp net mvc 3Aplicación abc. asp net mvc 3
Aplicación abc. asp net mvc 3
 
POOABD (POO Aplicada a B Datos) - API JDBC parte 2 -2020
POOABD (POO Aplicada a B Datos) - API JDBC parte 2 -2020POOABD (POO Aplicada a B Datos) - API JDBC parte 2 -2020
POOABD (POO Aplicada a B Datos) - API JDBC parte 2 -2020
 
JDBC
JDBCJDBC
JDBC
 
Tema 4
Tema 4Tema 4
Tema 4
 

Manual hibernate v2

  • 2. HIBERNATE ÍNDICE 1 INTRODUCCIÓN .................................................................................................................... 3 1.1 Object-Relational Mapping.......................................................................................... 3 1.2 Hibernate y MVC en entornos web ............................................................................. 5 2 MI PRIMERA APLICACIÓN CON HIBERNATE ......................................................................... 7 2.1 Pasos para crear una aplicación Hibernate ................................................................. 7 2.2 Desarrollo paso a paso................................................................................................. 8 3 FRAMEWORK HIBERNATE .................................................................................................. 38 3.1 Introducción............................................................................................................... 38 3.2 Instalación.................................................................................................................. 39 3.3 Configuración............................................................................................................. 39 3.4 El interfaz Session ...................................................................................................... 58 4 ASOCIACIONES.................................................................................................................... 62 4.1 Relaciones en Bases de datos .................................................................................... 63 4.2 Many-to-one .............................................................................................................. 65 4.3 Many-to-many ........................................................................................................... 67 4.4 One-to-one................................................................................................................. 69 5 RECUPERACIÓN DE DATOS ................................................................................................. 71 5.1 HQL ............................................................................................................................ 73 5.2 Criteria ....................................................................................................................... 83 5.3 SQL ............................................................................................................................. 89 [2]
  • 3. HIBERNATE 1. INTRODUCCIÓN 1.1.OBJECT-RELATIONAL MAPPING Hibernate es una implementación de mapeo Objeto-Relacional (ORM – Object-Relational Mapping). El objetivo de un ORM es hacer corresponder el modelo de datos de la aplicación con el modelo de clases de la misma, los cuales no son tan distintos como se pueda pensar. Para ello, Hibernate realiza el mapeo de elementos (tablas, columnas) entre una Base de datos relacional y objetos de la aplicación en cuestión: Base de Datos Relacional Modelo de Objetos TABLA Persona Persona Nombre Apellido Teléfono Juan López 666111122 -String nombre -String apellido Ana Hurtado 959121212 -String teléfono Francisco Soria 889121212 Belén Jiménez 789456123 instance: Persona nombre = Juan apellido = López teléfono = 666111122 [3]
  • 4. HIBERNATE Este tipo de sistema facilita todas las operaciones de persistencia y acceso a los datos desde la aplicación al presentar las siguientes características principales: Independiente de SQL: Hibernate incorpora funcionalidades para las operaciones simples de recuperación y actualización de datos para las cuales no será necesario utilizar las sentencias SELECT, INSERT, UPDATE o DELETE habituales, siendo sustituidas por llamadas a métodos (list, save, update, delete, …). Hibernate se encarga de generar la sentencia SQL que se encargará de realizar tales operaciones. De cualquier modo, se pueden especificar consultas SQL en caso necesario o incluso consultas en el dialecto de Hibernate, el HQL, con sintaxis similar a SQL pero que establece una serie de elementos propios del sistema ORM que gestiona. Independiente del SGBD: al aislar las funciones de manipulación de datos del lenguaje SQL, se consigue que la aplicación pueda comunicarse con cualquier SGBD ya que no existirán dependencias o particularidades en las sentencias de consulta o actualización de datos que harían a la aplicación dependiente de un SGBD en cuestión. El encargado de realizar la traducción final entre las operaciones Objeto-relacionales y las sentencias SQL es Hibernate, con lo cual el problema de la compatibilidad queda solventado. Incorpora soporte para la mayoría de los sistemas de bases de datos existentes. Independiente de JDBC: Hibernate contiene una API completa que aísla a la aplicación, no solamente de las operaciones con lenguaje SQL, sino también la utilización de objetos propios de la gestión de Bases de datos JDBC (Statement, ResultSet, …). Este tipo de objetos habituales en la programación Java de acceso a Bases de datos, se sustituye por el uso de objetos mucho más sencillos como colecciones de clases tipo JavaBeans que contendrán los datos de los almacenes de datos. [4]
  • 5. HIBERNATE 1.2.HIBERNATE Y MVC EN ENTORNOS WEB En una arquitectura MVC genérica como la siguiente, Hibernate juega un papel primordial como capa de persistencia de la aplicación. Como aparece en el esquema, los JavaBeans encargados de ejecutar la lógica de la aplicación interacturán con datos habitualmente almacenados en una Base de datos. Hibernate se introduce en este contexto para dar soporte de acceso y gestión de los datos a la capa de Modelo. El patrón MVC se utiliza de forma amplia en el desarrollo de aplicaciones web. Fuente: http://java.sun.com/blueprints/patterns/MVC-detailed.html [5]
  • 6. HIBERNATE Controller (Controlador): Servlet central que recibe las peticiones, procesa la URL recibida y delega el procesamiento a los JavaBeans. Servlet que almacena el resultado del procesamiento realizado por los JavaBeans en el contexto de la petición, la sesión o la aplicación. Servlet que transfiere el control a un JSP que lleva a cabo la presentación de resultados. Model (Modelo): JavaBeans (o EJBs para aplicaciones más escalables) que desempeñan el rol de modelo: Algunos beans ejecutan lógica. Otros guardan datos. Normalmente: El Servlet Controller invoca un método en un bean de lógica y éste devuelve un bean de datos. El programador del JSP tiene acceso a beans de datos. View (Vista): Rol ejecutado por JSPs. El Servlet Controller transfiere el control al JSP después de guardar en un contexto el resultado en forma de un bean de datos. JSP usa jsp:useBean y jsp:getProperty para recuperar datos y formatear respuesta en HTML o XML. En resumen: Los JavaBeans o EJBs ejecutan la lógica de negocio y guardan los resultados. Los JSPs proporcionan la información formateada. Los servlets coordinan/controlan la ejecución de los beans y los JSPs. [6]
  • 7. HIBERNATE 2. MI PRIMERA APLICACIÓN CON HIBERNATE Esta parte del manual es una guía paso a paso para realizar una aplicación sencilla, es tal vez la mejor manera de introducirse con Hibernate y es recomendable realizarla antes de leer el resto del manual ya que mejorará la comprensión de éste. Esta aplicación será desarrollada haciendo uso del IDE Netbeans 6.7. Se puede descargar de http://netbeans.org/. 2.2.PASOS PARA CREAR UNA APLICACIÓN HIBERNATE Estos son los pasos mínimos que se deberán seguir para desarrollar la aplicación satisfactoriamente. 1. Determinar el modelo de datos de la aplicación. 2. Añadir las librerías Java de Hibernate. 3. Definir las clases de persistencia. 4. Crear los ficheros de mapeo. 5. Configurar Hibernate. 6. Crear clases de ayuda. 7. Cargar y guardar objetos. 8. Ejecutar la primera versión. 9. Asociar clases. 10. Ejecutar la aplicación. [7]
  • 8. HIBERNATE 2.3.DESARROLLO PASO A PASO 1. Determinar el modelo de datos de la aplicación. Este ejemplo se trata de una sencilla introducción donde únicamente se dispone de dos clases Event y Person tanto en la base de datos del sistema como en el modelo de objetos de la aplicación. También se usarán clases auxiliares para la gestión del acceso y operaciones con los datos. En primer lugar, es necesario crear la Base de datos en MySQL. Su nombre será FirstApp pero no se van a crear tablas en la misma ya que se configurará una opción en el fichero de configuración de Hibernate (hibernate.cfg.xml) para que genere el esquema de la Base de datos al desplegar la aplicación. Como se ha comentado, la aplicación se creará a través de Netbeans. Este entorno de desarrollo dispone de herramientas para la configuración del acceso a la Base de datos. En primer lugar es posible que sea necesario configurar el driver de la base de datos que se va a utilizar en la aplicación, en este caso MySQL. Para ello es necesario seleccionar la opción New Connection… del menú del botón derecho del ratón sobre la opción Drivers. A continuación se selecciona el fichero .jar que contiene el driver de MySQL y se dejan el resto de campos con los valores que aparecen al seleccionarlo. Todo lo relacionado [8]
  • 9. HIBERNATE con la gestión de Drivers NO es propio de Hibernate, se está configurando el entorno de Netbeans para la utilización de los Asistentes existentes. Ahora hay que crear la conexión desde la pestaña Services seleccionando la opción New Connection… del menú del botón derecho del ratón sobre la opción Databases. [9]
  • 10. HIBERNATE Los datos que se completan son los correspondientes a la conexión con la base de datos que se encuentra en el servidor MySQL. 2. Añadir las librerías Java de Hibernate. Netbeans dispone de un asistente para la creación de aplicaciones Web donde se puede indicar que la aplicación empleará Hibernate. De esta forma, Netbeans realiza una serie de acciones de forma automática que ayudarán al desarrollo mediante este Framework. Se deberá crear un nuevo proyecto web con Netbeans, para ello dirigirse al menú: File New Project Web Web Application. No se debe olvidar añadir el Framework, como muestran las imágenes siguientes. [10]
  • 11. HIBERNATE Al crear el proyecto, Netbeans crea un fichero hibernate.cfg con los valores para conectar con la Base de datos que se ha establecido al crear el proyecto. Dicho archivo se encuentra en la carpeta Source Packagesdefault package de la aplicación. [11]
  • 12. HIBERNATE 3. Definir las clases de persistencia. El paso siguiente es añadir clases para representar a los elementos de la Base de datos. La clase Event (paquete events) es una clase tipo JavaBean sencilla, cuyas propiedades coinciden con los campos de la tabla Events que existirá en la Base de datos. package events; import java.util.Date; public class Event { private Long id; private String title; private Date date; public Event() { } public Long getId() { return id; } private void setId(Long id) { this.id = id; } public Date getDate() { return date; } public void setDate(Date date) { this.date = date; } public String getTitle() { return title; } public void setTitle(String title) { this.title = title; } } La propiedad id representa el identificador único para un evento. Todas las clases de persistencia deben tener un identificador si se quiere utilizar el conjunto completo de [12]
  • 13. HIBERNATE funcionalidades de Hibernate. El constructor sin argumentos también es un requisito para todas las clases persistentes. Se recomienda en la mayoría de las ocasiones utilizar clases para representar los tipos de los atributos en lugar de utilizar tipos básicos, debido a que para aquellos campos que se permitan valores nulos en la Base de datos, la representación del valor del campo será natural en la representación Java (null), mientras que con tipos básicos podría resultar en un error. En el paquete events también se introducirá la clase Person, la cual se representará de forma similar por el momento: package events; public class Person { private Long id; private int age; private String firstname; private String lastname; public Person() { } // getters y setters para todas las propiedades } 4. Crear los ficheros de mapeo. Para cada una de las clases de persistencia tiene que existir un fichero de mapeo que se encarga de definir la relación entre las tablas y columnas de éstas en la Base de datos, y las clases y sus propiedades en el modelo de objetos. En Netbeans existe una utilidad para mapear las clases con las tablas de la Base de datos de forma automática. Para ello, seleccionar la opción New Other Hibernate Hibernate Mapping File [13]
  • 14. HIBERNATE El nombre del fichero (Event.hbm.xml) coincidirá con el nombre de la clase que mapea y se guardará habitualmente en el mismo paquete donde se encuentra dicha clase. [14]
  • 15. HIBERNATE Solamente queda seleccionar la clase y la tabla a mapear. En este caso no se puede especificar ninguna tabla ya que la Base de datos se encuentra vacía. Al pulsar Finish se genera un archivo de mapeo, al cual es necesario añadir el nombre de la tabla que está mapeando, y completar con los datos del mapeo de las columnas. <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"> <hibernate-mapping> <class name="events.Event" table="EVENTS"> <id name="id" column="EVENT_ID"> <generator class="native"/> </id> <property name="date" type="timestamp" column="EVENT_DATE"/> <property name="title"/> </class> </hibernate-mapping> [15]
  • 16. HIBERNATE Algunos detalles sobre este archivo: <class name="events.Event" table="EVENTS"> Aunque inicialmente el archive se crea con una serie de propiedades para el mapeo (dynamic-insert="false" dynamic-update="false" …) se han eliminado para simplificar el ejemplo. Realmente las únicas propiedades imprescindibles son name (nombre de la clase) y table (nombre de la tabla). <id name="id" column="EVENT_ID"> En primer lugar se declara el identificador. Esta definición se destaca porque se identifica con la etiqueta id. La propiedad name representa el nombre del atributo en la clase, y la propiedad column el nombre del campo en la tabla. <generator class="native"/> Dentro del identificador se declara cómo se gestiona la asignación de ésta. En este caso se ha elegido el valor native, que delega la gestión de la clave en el SGBD utilizado, es decir, que no es necesario preocuparse de la gestión/asignación de claves de forma manual. Existen otras posibilidades de generadores de clave que se estudiarán más adelante en este documento. [16]
  • 17. HIBERNATE <property name="date" type="timestamp" column="EVENT_DATE"/> La siguiente propiedad en declararse es date. En este caso también name representa el nombre del atributo en la clase, y column el nombre del campo en la tabla. La propiedad type representa el tipo de datos que se va a utilizar, ya que aunque Hibernate es capaz de detectar que este campo se refiere a un valor de tipo Date, es necesario especificar si esa fecha se gestionará como time, date o timestamp. Esta propiedad type sirve para realizar conversiones de tipos si es necesario en la aplicación, de forma que un campo que en la base de datos es numérico se trate como String, o Boolean, … <property name="title"/> Por último se declara el campo title. En este caso solamente se especifica el nombre del atributo de la clase porque el nombre coincide con el nombre de la columna de la tabla de Base de datos, si no sería necesario especificar el nombre de dicha columna. El fichero de mapeo para la clase Person quedará de la siguiente forma: <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"> <hibernate-mapping> <class name="events.Person" table="PERSON"> <id name="id" column="PERSON_ID"> <generator class="native"/> </id> <property name="age"/> <property name="firstname"/> <property name="lastname"/> </class> </hibernate-mapping> [17]
  • 18. HIBERNATE 5. Configurar Hibernate. Hasta el momento se han creado las clases para representar los objetos de la Base de datos y los ficheros de mapeo para las mismas. Para que la aplicación funcione de forma correcta, es necesario configurar Hibernate a través de su fichero de configuración hibernate.cfg.xml. En este fichero se establecerá al menos la conexión con la base de datos, y se especificarán cuáles son los ficheros de mapeo que se están empleando en la aplicación, es decir, que si un fichero de mapeo no aparece en hibernate.cfg el mapeo no funcionará. El fichero hibernate.cfg se encuentra en el paquete por defecto de la aplicación. Si se abre este fichero con Netbeans, en primer lugar aparece la vista Diseño. Al seleccionar la vista XML (esquina superior izquierda de la ventana) aparecerá el código que Netbeans introdujo por defecto al crear la aplicación y especificar la conexión a la Base de datos que se iba a emplear en la misma: <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd"> <hibernate-configuration> <session-factory name="session1"> <property name="hibernate.dialect"> org.hibernate.dialect.MySQLDialect </property> <property name="hibernate.connection.driver_class"> com.mysql.jdbc.Driver </property> <property name="hibernate.connection.url"> jdbc:mysql://localhost:3306/firstapp </property> <property name="hibernate.connection.username">root</property> <property name="hibernate.connection.password">root</property> <mapping resource="events/Event.hbm.xml"/> <mapping resource="events/Person.hbm.xml"/> </session-factory> </hibernate-configuration> [18]
  • 19. HIBERNATE <session-factory name="session1"> Indica el session factory utilizado en la aplicación. Si la aplicación accede a más de una Base de datos es necesario declarar más de un session-factory, cada uno de ellos identificado por un nombre distinto. <property name="hibernate.dialect"> La propiedad dialect indica la variante de SQL que Hibernate genera a la hora de acceder a la Base de datos. Además de los datos de la conexión a la Base de datos y los ficheros de mapeo de la aplicación (que Netbeans ha introducido de forma automática al crear los propios ficheros hbm), en hibernate.cfg deben aparecer propiedades importantes que definen los siguientes aspectos: current_session_context_class: Hibernate funciona con sesiones para acceder a los datos. Es necesario definir una clase de gestión de sesiones para poder realizar operaciones con la Base de datos. cache.provider_class: especifica el comportamiento de la Caché de 2º nivel. show_sql: mostrar en los logs las sentencias SQL que Hibernate lanza cada vez que realiza una operación con la Base de datos. hbm2ddl.auto: crear el esquema de la Base de datos de forma automática al desplegar la aplicación. Los valores a añadir a hibernate.cfg para el ejemplo son los siguientes: <!-- Enable Hibernate's automatic session context management--> <property name="current_session_context_class">thread</property> <!-- Disable the second-level cache --> <property name="cache.provider_class">org.hibernate.cache.NoCacheProvider</property> <!-- Echo all executed SQL to stdout --> <property name="show_sql">true</property> <!-- Drop and re-create the database schema on startup --> <property name="hbm2ddl.auto">create</property> [19]
  • 20. HIBERNATE 6. Crear clases de ayuda. Una vez que se ha configurado Hibernate, ya se puede escribir el código Java para el acceso a los datos. Como se ha comentado anteriormente, Hibernate utiliza el concepto de sesión para acceder a los datos, de forma que cualquier operación de consulta o manipulación de los datos debe estar enmarcada en una sesión. Para que la gestión de sesiones quede aislada del resto de operaciones de acceso a datos, y para evitar la duplicidad de código, es habitual generar una clase de ayuda que se encarga de la inicialización de sesiones. Netbeans permite la generación de esta clase a través del menú New Other Hibernate HibernateUtil. En este caso la clase HibernateUtil se incorporará al paquete util. [20]
  • 21. HIBERNATE package util; import org.hibernate.cfg.Configuration; import org.hibernate.SessionFactory; public class HibernateUtil { private static final SessionFactory sessionFactory; static { try { // Create the SessionFactory from hibernate.cfg.xml sessionFactory = new Configuration().configure().buildSessionFactory(); } catch (Throwable ex) { // Log the exception. System.err.println("Initial SessionFactory creation failed." + ex); throw new ExceptionInInitializerError(ex); } } public static SessionFactory getSessionFactory() { return sessionFactory; } } [21]
  • 22. HIBERNATE Cuando una clase de la aplicación quiera acceder a la sesión actual, simplemente invocará al método estático getSessionFactory() (HibernateUtil.getSessionFactory()). 7. Cargar y guardar objetos. Para manipular los datos de la Base de datos se va a crear una clase EventManager en el paquete event para el almacenamiento y recuperación de eventos: public class EventManager { public void createAndStoreEvent(String title, Date theDate) { //Obtener la sesión actual Session session = HibernateUtil.getSessionFactory().getCurrentSession(); //Comenzar la transacción session.beginTransaction(); //Crear el evento Event theEvent = new Event(); theEvent.setTitle(title); theEvent.setDate(theDate); //Almacenarlo session.save(theEvent); //Confirmar transacción session.getTransaction().commit(); } public List listEvents() { //Obtener la sesión actual Session session = HibernateUtil.getSessionFactory().getCurrentSession(); //Comenzar la transacción session.beginTransaction(); //Obtener la lista de eventos List result = session.createQuery("from Event").list(); //Confirmar transacción session.getTransaction().commit(); return result; } } [22]
  • 23. HIBERNATE Los métodos que se han definido son los siguientes, los cuales se describen para comprobar la sencillez de las acciones que realizan: createAndStoreEvent: crea y almacena un evento realizando los siguientes pasos: 1. Acceder a la sesión actual: a través del método estático getSessionFactory() de la clase HibernateUtil creada anteriormente en el proyecto. 2. Abrir una transacción: utilizando la sesión actual. 3. Crear el objeto: de la forma habitual en Java. 4. Almacenar el objeto: simplemente invocando al método save del interfaz Session (sesión actual). 5. Confirmar la transacción: utilizando también la sesión actual. En la siguiente imagen se muestra un esquema del funcionamiento de Hibernate basado en sesiones: listEvents: obtiene una lista de todos los eventos de la Base de datos realizando los siguientes pasos: 1. Acceder a la sesión actual: a través del método estático getSessionFactory() de la clase HibernateUtil creada anteriormente en el proyecto. 2. Abrir una transacción: utilizando la sesión actual. Las consultas a bases de datos también requieren de una transacción en Hibernate. [23]
  • 24. HIBERNATE 3. Obtener el conjunto de resultados: se obtiene una colección (List) de instancias de la clase Event cuyos datos coincidirán con los datos de los registros existentes en la Base de datos. Existen varias formas de obtener datos de una tabla en Hibernate, en este caso se ha utilizado un Query HQL. Posteriormente se tratarán en profundidad los aspectos relacionados con los distintos tipos de consultas en Hibernate. 4. Confirmar la transacción: utilizando también la sesión actual. 8. Ejecutar la primera versión. Para probar lo que se ha implementado hasta el momento se va a crear una sencilla aplicación Web. Para ello en primer lugar se modificará la página index.jsp del proyecto para que funcione como formulario para introducir los datos: <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=windows-1252"> <title>JSP Page</title> </head> <body> <form action="Servlet"> <table> <tr> <td>title</td><td><input type="text" name="title"></input></td> </tr> <tr> <td>date</td><td><input type="text" name="date"></input></td> </tr> <tr> <td><input type="submit"/></td> </tr> </table> </form> </body> </html> [24]
  • 25. HIBERNATE A continuación se crea el Servlet que se encargará de la lógica de la aplicación. Para crear un Servlet Netbeans también dispone de un Asistente a través de la opción New Other Web Servlet Su nombre será Servlet y se almacenará en el paquete servlet. En la siguiente pantalla se dejan por defecto los parámetros que se añadirán al fichero web.xml. [25]
  • 26. HIBERNATE Para ejecutar la aplicación simplemente usar la opción Run Run Main Project (F6). public class Servlet extends HttpServlet { protected void processRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType("text/html;charset=UTF-8"); PrintWriter out = response.getWriter(); try { EventManager mng = new EventManager(); //Parsear la fecha Date date = new SimpleDateFormat("dd/MM/yyyy"). parse(request.getParameter("date")); mng.createAndStoreEvent(request.getParameter("title"), date); //Mostrar los datos almacenados this.mostrarTabla(out, mng.listEvents()); } catch (Exception ex) { out.println(ex); } finally { out.close(); } } private void mostrarTabla(PrintWriter out, List lista) { out.println("<table>"); Iterator it = lista.iterator(); //Iterar sobre todos los eventos while (it.hasNext()) { Event event = (Event) it.next(); out.println("<tr>"); out.println("<td>" + event.getTitle() + "</td>"); out.println("<td>" + event.getDate() + "</td>"); out.println("</tr>"); } out.println("</table>"); } protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { processRequest(request, response); } } [26]
  • 27. HIBERNATE 9. Asociar clases. La asociación entre clases es uno de los aspectos más importantes de Hibernate, así como la asociación entre tablas es la base del modelo relacional de Bases de datos. Este aspecto puede resultar complejo en algunas ocasiones. Posteriormente se tratarán en profundidad los aspectos relacionados con los distintos tipos de asociaciones en Hibernate. En los pasos 3 y 4 se definieron las clases Event y Person a través de código Java y ficheros de mapeo. Ahora es necesario modelar la relación que existe entre ambas a través de una asociación Hibernate. La relación que existe entre ambas tablas es una relación M a M, de forma que a un Evento acudirán varias Personas, y una Persona puede acudir a diversos Eventos. A nivel de Bases de datos, esta relación dará lugar a una tabla intermedia PERSON_EVENT. Esta relación en Hibernate se puede modelar de diversas maneras, y además se puede reflejar de distintas formas en las clases implicadas. En primer lugar, la relación más sencilla que se puede establecer es la relación Unidireccional entre 2 tablas, en este caso entre las tablas Person y Person_Event. Para el ejemplo, el tipo de relación escogido es algo complejo, denominado en Hibernate como relación con tabla intermedia (join table). En el capítulo 4 se explicarán los tipos de relaciones más generales, y la forma de eludir las relaciones complejas, pero es bueno presentar en el ejemplo otro tipos de relaciones que pueden encontrarse en aplicaciones Hibernate. Las relaciones se modelan con colecciones, normalmente conjuntos (Set) de forma que se agregan los fragmentos de código que aparecen a continuación. En la clase simplemente se crea el atributo de la clase Set y se generan los métodos get/set para el mismo. [27]
  • 28. HIBERNATE private Set events = new HashSet(); public Set getEvents() { return events; } public void setEvents(Set events) { this.events = events; } <set name="events" table="PERSON_EVENT"> <key column="PERSON_ID"/> <many-to-many column="EVENT_ID" class="events.Event"/> </set> En Person.hbm.xml se genera una nueva propiedad para la tabla de tipo conjunto. Los atributos de esa propiedad son los siguientes: name: nombre de la propiedad de la clase a la que hace referencia. table: tabla intermedia de la base de datos. key: clave de la tabla intermedia (PERSON_EVENT) que aporta la clase actual. La propiedad columna es el nombre de la columna de la tabla de Base de datos. Es decir, esta etiqueta significa que el nombre del campo que relaciona a la tabla que modela la clase Person (PERSON) y a la tabla intermedia (PERSON_EVENT) es PERSON_ID, el cual estará relacionado con el campo id de la clase Person (en este caso también se denomina PERSON_ID). many-to-many: indica para la tabla intermedia (PERSON_EVENT) cuál es la otra clase que está implicada en la relación (la clase Event) y cuál es la clave foránea que esta clase aporta a la relación. Con todo esto únicamente se ha posibilitado que a través de una persona concreta, es decir, una instancia de la clase Person, se pueda conocer de forma directa los eventos a los cuales está asociada. En Hibernate esto se traduce en acceder simplemente a los atributos de dicha clase. Por ejemplo, el método getEvents devuelve un Set con los eventos asociados a una persona: [28]
  • 29. HIBERNATE Person aPerson = (Person) session.load(Person.class, personId); aPerson.getEvents(); Esta utilidad es suficiente, pero se pueden realizar cosas más avanzadas, como manipular objetos persistentes y luego transformarlos en acciones contra la base de datos. Por ejemplo, el siguiente método asigna un evento a una persona de forma sencilla, sin gestionar claves ni relaciones entre tablas, simplemente a través de la relación normal entre conjuntos: public void addPersonToEvent(Long personId, Long eventId) { //Obtener la sesión actual Session session = HibernateUtil.getSessionFactory().getCurrentSession(); //Comenzar la transacción session.beginTransaction(); //Cargar la persona por clave Person aPerson = (Person) session.load(Person.class, personId); //Cargar el evento por clave Event anEvent = (Event) session.load(Event.class, eventId); //Agregar el evento a la persona aPerson.getEvents().add(anEvent); //Confirmar transacción session.getTransaction().commit(); } La línea aPerson.getEvents().add(anEvent) es donde se crea la relación entre ambos elementos, y al realizar la confirmación en la Base de datos se crean los registros necesarios para satisfacer dicha relación. A continuación se va a modelar la relación inversa. Una relación en Hibernate se puede modelar de forma unidireccional o bidireccional. Para el segundo de los casos, se establecen en los ficheros de configuración 2 relaciones, por una parte la relación directa (que corresponde con la que ya se ha generado en el ejemplo), y por la otra parte se modela la relación inversa. Es decir, si en el ejemplo la relación directa servía para conocer cuáles eran los eventos a los que estaba asociada una persona, la relación inversa proporciona información sobre cuáles son las personas que participan en un determinado evento. [29]
  • 30. HIBERNATE Para ello, en la clase Event se establece también una propiedad de tipo Set que almacenará los datos de las personas asociadas a un evento concreto: private Set participants = new HashSet(); public Set getParticipants() { return participants; } public void setParticipants(Set participants) { this.participants = participants; } El mapeo es muy similar al que se estableció para la clase Person, teniendo en cuenta que hay que incluir la propiedad inverse (con valor true): name: nombre de la propiedad de la clase a la que hace referencia. table: tabla intermedia de la base de datos. inverse: en toda relación bidireccional uno de los 2 extremos debe ser inverse=true, lo cual es utilizado por Hibernate a la hora de construir las sentencias SQL para interactuar con la Base de datos. key: el nombre del campo que relaciona a la tabla que modela la clase Event (EVENT) y a la tabla intermedia (PERSON_EVENT) es EVENT_ID, el cual estará relacionado con el campo id de la clase Event (EVENT_ID). many-to-many: indica para la tabla intermedia (PERSON_EVENT) cuál es la otra clase que está implicada en la relación (la clase Person) y cuál es la clave foránea que esta clase aporta a la relación (PERSON_ID). <set name="participants" table="PERSON_EVENT" inverse="true"> <key column="EVENT_ID"/> <many-to-many column="PERSON_ID" class="events.Person"/> </set> [30]
  • 31. HIBERNATE Gracias a esta nueva relación se pueden conocer las personas que pertenecen a un determinado evento. La pregunta es, ¿funcionará correctamente un método como el siguiente? public void addPersonToEvent(Long personId, Long eventId) { //Obtener la sesión actual Session session = HibernateUtil.getSessionFactory().getCurrentSession(); //Comenzar la transacción session.beginTransaction(); //Cargar la persona por clave Person aPerson = (Person) session.load(Person.class, personId); //Cargar el evento por clave Event anEvent = (Event) session.load(Event.class, eventId); //Agregar la persona al evento anEvent.getParticipants().add(aPerson); //Confirmar transacción session.getTransaction().commit(); } 10. Ejecutar la aplicación. Para probar todos los conceptos vistos hasta el momento, se crea un nuevo Servlet de la misma forma especificada en el paso 8, donde se realizarán las siguientes pruebas: Cargar eventos por clave (emng.loadEvent(new Long(1))), para comprobar si existe un evento con identificador igual a 1. Almacenar personas (mng.createAndStorePerson(…): almacena una persona de prueba. Agregar personas a eventos (mng.addPersonToEvent(new Long(1), e.getId())): agrega la persona creada anteriormente al evento. Listar participantes de un evento (e.getParticipants()): obtiene la lista de participantes al evento para mostrar sus nombres y la lista de eventos. [31]
  • 32. HIBERNATE public class ServletP extends HttpServlet { protected void processRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType("text/html;charset=UTF-8"); PrintWriter out = response.getWriter(); try { PersonManager mng = new PersonManager(); //Comprobar que existe el evento con id=1 EventManager emng = new EventManager(); Event e = emng.loadEvent(new Long(1)); if (e == null) { //No existe el evento out.println("Debe crear un evento"); } else { //Almacenar mng.createAndStorePerson(new Integer(30), "José", "Guardiola"); //Agregar un evento como prueba (id=1) mng.addPersonToEvent(new Long(1), e.getId()); //Refrescar los datos e = emng.loadEvent(new Long(1)); //Mostrar los datos almacenados en el evento this.mostrarTabla(out, e.getParticipants()); } } catch (Exception ex) { out.println(ex); } finally { out.close(); } } [32]
  • 33. HIBERNATE private void mostrarTabla(PrintWriter out, Set lista) { out.println("<table>"); Iterator it = lista.iterator(); //Iterar sobre todos los eventos while (it.hasNext()) { Person p = (Person) it.next(); out.println("<tr>"); out.println("<td>" + p.getAge() + "</td>"); out.println("<td>" + p.getFirstname() + "</td>"); out.println("<td>" + p.getLastname() + "</td>"); out.println("<td>" + p.getEvents() + "</td>"); out.println("</tr>"); } out.println("</table>"); } } Ejemplo: 1. En primer lugar se crea un evento. 2. A continuación se pulsa el enlace Prueba relaciones. 3. Tras la ejecución del código del Servlet se muestra la lista de participantes en el evento inicial. Para el ejemplo, la persona que se almacena como prueba estará al menos en el evento creado inicialmente. [33]
  • 34. HIBERNATE El código del Servlet resulta sencillo ya que toda la lógica de interacción con Hibernate se encuentra en las clases PersonManager y EventManager, destacando la forma en que se han realizado las operaciones basadas en relaciones: Agregar personas a eventos (mng.addPersonToEvent(new Long(1), e.getId())): la persona se agrega al evento a través del conjunto de eventos en los que participa una persona (ver PersonManager). Listar participantes de un evento (e.getParticipants()): los participantes a un evento se obtienen a través del conjunto de personas que participa en un evento. Para ello se carga el evento, se obtienen sus participantes, y para cada uno de ellos se muestra su nombre y la lista de eventos en los cuales participa. El método loadPerson carga una persona a través del valor de su campo clave (id). Para ello se utiliza el método load del interfaz Session. El procedimiento de recuperación de una instancia también sigue el esquema de sesiones y transacciones explicado con anterioridad. El método listPerson devuelve un listado de todas las personas a través de un Criteria. Esta forma de recuperar datos se explica en el capítulo 5.2 con detenimiento, pero por el momento destacar que el método setFetchMode posibilita la recuperación de datos relacionados, es decir, Hibernate por defecto no cargará los datos de los conjuntos que estén relacionados con una instancia (por ejemplo, los eventos a los que está asociada una persona) para no sobrecargar innecesariamente al sistema, así que en caso de querer recuperarlos hay que notificarlo de esta forma, entre otras. [34]
  • 35. HIBERNATE public class EventManager { /** * Almacenar un evento * @param title título * @param theDate fecha */ public void createAndStoreEvent(String title, Date theDate) { //Obtener la sesión actual Session session = HibernateUtil.getSessionFactory().getCurrentSession(); //Comenzar la transacción session.beginTransaction(); //Crear el evento Event theEvent = new Event(); theEvent.setTitle(title); theEvent.setDate(theDate); //Almacenarlo session.save(theEvent); //Confirmar transacción session.getTransaction().commit(); } /** * Cargar un evento * @return evento */ public Event loadEvent(Long eventId) { //Obtener la sesión actual Session session = HibernateUtil.getSessionFactory().getCurrentSession(); //Comenzar la transacción session.beginTransaction(); //Cargar el evento por clave [35]
  • 36. HIBERNATE Event anEvent = (Event) session.createCriteria(Event.class). setFetchMode("participants", FetchMode.JOIN). setFetchMode("participants.events", FetchMode.JOIN). add(Restrictions.eq("id", eventId)). uniqueResult(); //Confirmar transacción session.getTransaction().commit(); return anEvent; } /** * Listar los eventos * @return lista de eventos */ public List listEvents() { //Obtener la sesión actual Session session = HibernateUtil.getSessionFactory().getCurrentSession(); //Comenzar la transacción session.beginTransaction(); //Obtener la lista de personas List result = session.createCriteria(Event.class). setFetchMode("participants", FetchMode.JOIN). list(); //Confirmar transacción session.getTransaction().commit(); return result; } } El método loadEvent carga un evento a través del valor de su campo clave (id). Para ello se utiliza un Criteria al cual se le añade una restricción de igualdad (Restrictions.eq) para filtrar por el campo clave (id). Además se utilizan los métodos necesarios para que se carguen los participantes de un evento [36]
  • 37. HIBERNATE (setFetchMode("participants", FetchMode.JOIN)) y para cada uno de dichos participantes, que en su propiedad events (ver clase Person) se carguen los datos de sus eventos (setFetchMode("participants", FetchMode.JOIN)). De esta forma, para cada evento se podrían conocer los datos completos de las personas asociadas (edad, nombre, apellidos y eventos a los que se encuentra asociada). El método uniqueResult indica que la consulta deberá devolver un único valor, el cual es una instancia de la clase solicitada. Para estas 2 clases, los ficheros de mapeo quedan configurados según los cambios que se han comentado al introducir las relaciones entre ambas. Para ejecutar el proyecto simplemente queda modificar la página JSP de inicio, para que incluya la opción Prueba relaciones: <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=windows-1252"> <title>JSP Page</title> </head> <body> <form action="Servlet"> <table> <tr> <td>title</td><td><input type="text" name="title"></input></td> </tr> <tr> <td>date</td><td><input type="text" name="date"></input></td> </tr> <tr> <td><input type="submit"/></td> </tr> </table> </form> <a href="ServletP">Prueba relaciones</a> </body> </html> [37]
  • 38. HIBERNATE 3. FRAMEWORK HIBERNATE 3.1.INTRODUCCIÓN En el desarrollo de una aplicación J2EE se trabaja continuamente con objetos. Sin embargo, las bases de datos relacionales no trabajan con ellos, sino con conjuntos y relaciones entre conjuntos. Entonces ¿Cómo se almacena un objeto en una base de datos? ¿Y cómo se mantienen las relaciones cuando se convierte un elemento de una base de datos en un objeto Java? La causa de esta disparidad es la llamada diferencia Objeto-Relacional. El problema se agrava cuanto más complejo sea el material a trasladar de un paradigma a otro. En estos casos se hace necesario un puente entre ambos conceptos. Es lo que se llama un mapeador objeto-relacional, también conocido por sus siglas en inglés ORM (Object-Relational Mapping). Un ORM permite al programador aislarse de los detalles básicos. Basta definir cómo se deben trasladar los datos entre ambos modelos y el mapeador se encargará de aplicarlo en cada ocasión. Hibernate es un potente servicio de consulta y persistencia objeto/relacional con el cual es posible desarrollar clases persistentes mediante lenguajes orientados a objetos manteniendo sus características básicas (incluyendo herencia, polimorfismo, colecciones, etc...). Permite expresar consultas tanto en SQL como en su propia extensión de este lenguaje, denominada HSQL. Hibernate es un proyecto de software libre con código abierto, por lo que su desarrollo se encuentra en continua evolución. La página del proyecto: http://www.hibernate.org/ [38]
  • 39. HIBERNATE 3.2.INSTALACIÓN IMPORTANTE: Este apartado sirve como guía de ayuda de instalación manual de Hibernate para su uso dentro de una aplicación. No es recomendable realizar la instalación de Hibernate “a mano”. Normalmente, se utilizan entornos de desarrollo integrados como Netbeans, con los que se puede elegir durante la creación del proyecto que añada los frameworks deseados, entre ellos Hibernate, de forma que el entorno los configurará adecuadamente de forma automática. En caso de que se descargue la última versión, se recomienda seguir la ayuda oficial ya que estas instrucciones pueden estar obsoletas. 1. Descargar la distribución de Hibernate Core de: https://www.hibernate.org/344.html 2. Descomprimir el fichero 3. Copiar los archivos jar necesarios a la carpeta lib de nuestra aplicación: a. hibernate3.jar b. librequired*.jar c. liboptional*.jar 4. Crear el fichero hibernate.cfg.xml en el paquete por defecto de la aplicación. 3.3.CONFIGURACIÓN Hibernate se configura a través hibernate.cfg.xml. En el paso 5 del ejemplo anterior se explicaron algunos de los elementos de configuración que se pueden encontrar en este fichero: [39]
  • 40. HIBERNATE <?xml version=”1.0” encoding=”UTF-8”?> <!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd"> <hibernate-configuration> <session-factory name="session1"> <property name="hibernate.dialect"> org.hibernate.dialect.MySQLDialect </property> <property name="hibernate.connection.driver_class"> com.mysql.jdbc.Driver </property> <property name="hibernate.connection.url"> jdbc:mysql://localhost:3306/firstapp </property> <property name="hibernate.connection.username">root</property> <property name="hibernate.connection.password">root</property> <!-- Enable Hibernate's automatic session context management--> <property name="current_session_context_class">thread</property> <!-- Disable the second-level cache --> <property name="cache.provider_class"> org.hibernate.cache.NoCacheProvider </property> <!-- Echo all executed SQL to stdout --> <property name="show_sql">true</property> <!-- Drop and re-create the database schema on startup --> <property name="hbm2ddl.auto">create</property> <mapping resource="events/Event.hbm.xml"/> <mapping resource="events/Person.hbm.xml"/> </session-factory> </hibernate-configuration> [40]
  • 41. HIBERNATE Este archivo es leído por el framework cuando arranca y contiene los siguientes elementos: Sesiones: session factory utilizados en la aplicación. Si la aplicación accede a más de una Base de datos es necesario declarar más de un session-factory, cada uno de ellos identificado por un nombre distinto. Propiedades: dentro de cada sesión se declaran una serie propiedades para la conexión y configuración del acceso a la Base de datos: Datos de la conexión: datos para conectar con la Base de datos. hibernate.connection.driver_class Driver JDBC de la Base de datos hibernate.connection.url URL de conexión a la Base de datos hibernate.connection.username Usuario hibernate.connection.password Clave hibernate.connection.pool_size Máximo número de conexiones del pool Propiedades de configuración: parámetros de configuración generales. hibernate.max_fetch_depth Profundidad máxima de joins para relaciones simples hibernate.default_batch_fetch_size Tamaño por defecto para el fetching de asociaciones hibernate.default_entity_mode Modo por defecto para la dynamic-map representación de entidades dom4j pojo hibernate.order_updates Ordenar las actualizaciones true por clave primaria false hibernate.generate_statistics Generar estadísticas de true rendimiento false hibernate.use_identifier_rollback Resetea el identificador true asociado en caso de false eliminación hibernate.use_sql_comments Genera comentarios en las true sentencias SQL false [41]
  • 42. HIBERNATE Propiedades de conexión: otras propiedades de la conexión. hibernate.jdbc.fetch_size Tamaño de búsqueda hibernate.jdbc.batch_size Actualización batch de JDBC2 Utilizar el rowcount que devuelve true hibernate.jdbc.batch_versioned_data executeBatch() false Seleccionar un hibernate.jdbc.factory_class org.hibernate.jdbc.Batcher propio Uso de resultsets scrollables de true hibernate.jdbc.use_scrollable_resultset JDBC2 false Uso de streams para la escritura true hibernate.jdbc.use_streams_for_binary de tipos de datos serializables false Uso de getGeneratedKeys() de true hibernate.jdbc.use_get_generated_keys JDBC3 false Uso de un ConnectionProvider hibernate.connection.provider_class propio true hibernate.connection.autocommit Habilita el Autocommit false auto Modo de Liberación de conexiones on_close hibernate.connection.release_mode JDBC after_transaction after_statement Propiedad específica de JDBC para hibernate.connection.<propertyName> la conexión Propiedad específica de JNDI para hibernate.jndi.<propertyName> la conexión Nivel de aislamiento de hibernate.connection.isolation transacciones [42]
  • 43. HIBERNATE Propiedades de caché: gestión de la caché de segundo nivel. Nombre de CacheProvider hibernate.cache.provider_class propio. Optimizar la operación de la true hibernate.cache.use_minimal_puts caché al mínimo número de false escrituras. true hibernate.cache.use_query_cache Habilitar la cache de consultas false Deshabilitar completamente la true hibernate.cache.use_second_level_cache cache false Nombre de un interfaz hibernate.cache.query_cache_factory QueryCache propio Prefijo de los nombres hibernate.cache.region_prefix regionales de la caché true hibernate.cache.use_structured_entries Usar entradas de cache legibles false Propiedades de transacciones: gestión de transacciones. Nombre de la factoría de hibernate.transaction.factory_class transacciones Nombre para obtener la jta.UserTransaction transacción JTA Nombre del hibernate.transaction.manager_lookup_class TransactionManagerLookup La sesión se lanza antes de true hibernate.transaction.flush_before_completion concluir la transacción false Cierra la sesión tras concluir la true hibernate.transaction.auto_close_session transacción false [43]
  • 44. HIBERNATE Otras propiedades. Estrategia para jta obtener la sesión thread hibernate.current_session_context_class actual managed custom Class org.hibernate.hql.ast. ASTQueryTranslatorFactory Implementación del hibernate.query.factory_class HQL Parser org.hibernate.hql.classic. ClassicQueryTranslatorFactory Mapeo a consultas hibernate.query.substitutions SQL validate Genera el esquema update hibernate.hbm2ddl.auto automáticamente al create crear la Sesión create-drop Utilización de CGLIB true hibernate.cglib.use_reflection_optimizer en lugar de reflexión false Mapeos: ficheros de mapeo de clases (hbm.xml) que se utilizan en la aplicación. 3.3.1. MAPEOS Los ficheros de mapeo que se utilizan en la aplicación se definen en hibernate.cfg, indicando la ruta donde se encuentran los mismos. Cada uno de estos ficheros con extensión hbm.xml mapean una clase de la aplicación con una de las tablas de la Base de datos especificada en la conexión, y contienen los detalles de dicho mapeo. [44]
  • 45. HIBERNATE Los ficheros de mapeo normalmente incluyen el nombre de la tabla y clase relacionadas, y el detalle del mapeo entre columnas de la tabla y propiedades de la clase, como puede observarse en la ilustración anterior. Un fichero de mapeo puede contener varias clases mapeadas, aunque habitualmente se realiza con una sola clase (cuyo nombre debería coincidir con el nombre del fichero de mapeo). Los elementos básicos de un fichero de mapeo aparecen a continuación. Se marcarán en negrita aquellos elementos importantes para su utilización: 1. hibernate-mapping: datos generales del mapeo. <hibernate-mapping schema="schemaName" (a) catalog="catalogName" (b) default-cascade="cascade_style" (c) default-access="field|property|ClassName" (d) default-lazy="true|false" (e) auto-import="true|false" (f) package="package.name" (g) /> a. schema (opcional): nombre del esquema de bases de datos. b. catalog (opcional): nombre del catálogo de la base de datos. c. default-cascade (opcional – none por defecto): estilo de cascada por defecto. [45]
  • 46. HIBERNATE d. default-access (opcional – property por defecto): estrategia de acceso a las propiedades. e. default-lazy (opcional – true por defecto): valor por defecto del atributo lazy de los mapeos de clases y colecciones. f. auto-import (opcional – true por defecto): permite usar nombres de clases sin calificar en el lenguaje SQL. Si hay dos clases con el mismo nombre sin calificar, esta propiedad tiene que tener el valor false. g. package (opcional): prefijo de paquete para los nombres de clases sin cualificar. 2. class: datos de la clase persistente y su relación con la tabla de la base de datos. <class name="ClassName" (a) table="tableName" (b) discriminator-value="discriminator_value" (c) mutable="true|false" (d) schema="owner" (e) catalog="catalog" (f) proxy="ProxyInterface" (g) dynamic-update="true|false" (h) dynamic-insert="true|false" (i) select-before-update="true|false" (j) polymorphism="implicit|explicit" (k) where="arbitrary sql where condition" (l) persister="PersisterClass" (m) batch-size="N" (n) optimistic-lock="none|version|dirty|all" (o) lazy="true|false" (p) entity-name="EntityName" (q) check="arbitrary sql check condition" (r) rowid="rowid" (s) subselect="SQL expression" (t) abstract="true|false" (u) node="element-name" /> [46]
  • 47. HIBERNATE a. name (opcional): nombre completo de la clase o interfaz Java. También se pueden hacer persistentes clases estáticas internas. b. table (opcional – por defecto el nombre de la clase sin cualificar): nombre de la tabla de la base de datos. c. discriminator-value (opcional – por defecto el nombre de la clase): distingue subclases individuales, se usa para comportamiento polimórfico. d. mutable (opcional – true por defecto): especifica si las instancias son mutables o no. Las clases inmutables no se pueden modificar ni eliminar. e. schema (opcional): sobreescribe el nombre de esquema especificado por <hibernate-mapping>. f. catalog (opcional): sobreescribe el nombre de catálogo especificado por <hibernate-mapping>. g. proxy (opcional): interfaz de proxy para la incialización perezosa. h. dynamic-update (opcional – false por defecto): la sentencia SQL UPDATE se genera en tiempo de ejecución y solamente contiene las columnas cuyos valores hayan cambiado. i. dynamic-insert (opcional – false por defecto): la sentencia SQL INSERT se genera en tiempo de ejecución y solamente contiene las columnas cuyos valores son distintos a null. j. select-before-update (opcional – false por defecto): se produce una sentencia SELECT antes de actualizar para comprobar si un objeto ha sido modificado. Si no no se produce dicha actualización. k. polymorphism (opcional – implicit por defecto): determina si se utiliza polimorfismo implícito o explícito a la hora de recuperar objetos en las consultas. l. where (opcional): condición WHERE a utilizar cuando se recuperan objetos de esta clase. m. persister (opcional): especifica un ClassPersister propio, permitiendo la redefinición de la estrategia de almacenamiento persistente. n. batch-size (opcional – 1 por defecto): tamaño batch para la búsqueda de instancias de esta clase por campo clave. [47]
  • 48. HIBERNATE o. optimistic-lock (opcional – version por defecto): determina la estrategia de bloqueo optimista. p. lazy (opcional): búsqueda perezosa. q. entity-name (opcional – por defecto el nombre de la clase): Hibernate3 permite mapear una misma clase distintas veces (con distintas tablas), y este nombre será el utilizado. r. check (opcional): expression SQL para generar una comprobación en la generación automática de esquemas. s. rowid (opcional): utilización de ROWID. t. subselect (opcional): mapea una entidad immutable de solo lectura con una subconsulta de la base de datos, por ejemplo para usar vistas en lugar de tablas. u. abstract (opcional): marca superclases abstractas en jerarquías con <union- subclass>. 3. id: dentro de la etiqueta class, se debe mapear la clave primaria de la tabla. <id name="propertyName" (a) type="typename" (b) column="column_name" (c) unsaved-value="null|any|none|undefined|id_value" (d) access="field|property|ClassName"> (e) node="element-name|@attribute-name|element/@attribute|." <generator class="generatorClass"/> </id> a. name (opcional): nombre de la propiedad. b. type (opcional): indica el tipo. c. column (opcional –nombre de la propiedad por defecto): nombre de la columna. [48]
  • 49. HIBERNATE d. unsaved-value (opcional): valor del identificador que indica que la instancia es nueva, para distinguir de instancias guardadas o cargadas en sesiones anteriores. Casi nunca se utiliza en Hibernate 3. e. access (opcional – property por defecto): estrategia de acceso al valor de la propiedad. 4. generator: dentro del id, es necesario definir un generador de identificadores únicos para la clase. <generator class="org.hibernate.id.TableHiLoGenerator"> <param name="table">uid_table</param> <param name="column">next_hi_value_column</param> </generator> a. class: nombre de la clase que implementa el interfaz org.hibernate.id.IdentifierGenerator, a la cual se pueden pasar parámetros a través de los elementos <param>. Asimismo, existe una serie de clases predefinidas: i. increment: identificadores únicos siempre que no existan otros procesos insertando en la tabla. ii. identity: columna de tipo identity (autonumérica) para aquellos sistemas que la soportan. iii. sequence: asignación basada en secuencia para aquellos sistemas que la soportan. iv. hilo: genera identificadores con un algoritmo hi/lo dado un nombre de tabla y de columna. v. seqhilo: genera identificadores con un algoritmo hi/lo dado un nombre de secuencia. vi. uuid: genera claves de tipo uuid de tamaño 32. vii. guid: usa una cadena guid generada por la base de datos para aquellos sistemas que la soportan. [49]
  • 50. HIBERNATE viii. native: selecciona identity, sequence o hilo dependiendo de la base de datos en uso. ix. assigned: asignado por la aplicación. Es la opción por defecto si no se incluye generator. x. select: asignación por trigger. xi. foreign: usa el identificador de otro objeto asociado, normalmente a través de un <one-to-one>. xii. sequence-identity: usa una secuencia y el método getGeneratedKeys de JDBC3 para la generación. 5. composite-id: utilizado en el caso que la clave primaria esté compuesta por más de una columna. <composite-id name="propertyName" (a) class="ClassName" (b) mapped="true|false" (c) access="field|property|ClassName"> (d) node="element-name|." <key-property name="propertyName" type="typename" column="column_name"/> (e) <key-many-to-one name="propertyName class="ClassName" column="column_name"/> (f) ...... </composite-id> a. name (opcional): nombre de la propiedad. b. class (opcional): la forma de implementar una clave compuesta en Hibernate es a través de una clase. Esta propiedad indica el nombre de dicha clase, que contendrá atributos para cada una de las columnas que componen la clave. c. mapped (opcional – false por defecto): utilización de un identificador compuesto mapeado. d. access (opcional – property por defecto): estrategia de acceso al valor de la propiedad. [50]
  • 51. HIBERNATE e. key-property: dentro de la etiqueta composite-id, indica cada uno de los campos que forman la clave y que no corresponden a claves foráneas de otras tablas: i. name: nombre de la propiedad (de la clase que implementa el identificador). ii. type (opcional): tipo Hibernate de la propiedad. iii. column (opcional – nombre de la propiedad por defecto): nombre de la columna. f. key-many-to-one: dentro de la etiqueta composite-id, indica cada uno de los campos que forman la clave y que corresponden a claves foráneas de otras tablas: i. name: nombre de la propiedad (de la clase que implementa el identificador). ii. class: nombre de la clase relacionada a través de la clave foránea. iii. column (opcional – nombre de la propiedad por defecto): nombre de la columna. 6. property: declaración de propiedades de la clase. <property name="propertyName" (a) column="column_name" (b) type="typename" (c) update="true|false" (d) insert="true|false" (e) formula="arbitrary SQL expression" (f) access="field|property|ClassName" (g) lazy="true|false" (h) unique="true|false" (i) not-null="true|false" (j) optimistic-lock="true|false" (k) generated="never|insert|always" (l) node="element-name|@attribute-name|element/@attribute|." index="index_name" unique_key="unique_key_id" length="L" precision="P" scale="S" /> [51]
  • 52. HIBERNATE a. name: nombre de la propiedad (primera letra siempre en minuscule). b. column (opcional – nombre de la propiedad por defecto): nombre de la columna de base de datos mapeada. También puede ser especificado a través de etiquetas <column>. c. type (opcional): indica el tipo Hibernate, que puede tratarse de uno de los siguientes, aunque en caso de no especificar Hibernate lo asignará automáticamente en función del tipo de la columna de base de datos: i. Tipo básico Hibernate (integer, string, character, date, …). ii. Clase Java o tipo básico (int, float, java.util.Date, …). iii. Clase Java serializable. iv. Clase propia. d. update (opcional – true por defecto): las columnas mapeadas deben incluirse en las sentencias UPDATE. e. insert (opcional – true por defecto): las columnas mapeadas deben incluirse en las sentencias INSERT. f. formula (opcional): expresión SQL que define el valor de una propiedad calculada. Las propiedades calculadas no se mapean a ninguna columna. g. access (opcional – property por defecto): estrategia utilizada para acceder a la propiedad. h. lazy (opcional – false por defecto): indica si esta propiedad debe ser buscada de forma perezosa cuando la instancia se accede por vez primera. i. unique (opcional): restricción unique para esta columna. j. not-null (opcional): restricción not-null para esta columna. k. optimistic-lock (opcional – true por defecto): las actualizaciones de esta propiedad requieren la adquisición del bloqueo optimista. l. generated (opcional – never por defecto): esta propiedad es generada por la base de datos. 7. many-to-one [52]
  • 53. HIBERNATE <many-to-one name="propertyName" (a) column="column_name" (b) class="ClassName" (c) cascade="cascade_style" (d) fetch="join|select" (e) update="true|false" (f) insert="true|false" (g) property-ref="propertyNameFromAssociatedClass" (h) access="field|property|ClassName" (i) unique="true|false" (j) not-null="true|false" (k) optimistic-lock="true|false" (l) lazy="proxy|no-proxy|false" (m) not-found="ignore|exception" (n) entity-name="EntityName" (o) formula="arbitrary SQL expression" (p) node="element-name|@attribute-name|element/@attribute|." embed-xml="true|false" index="index_name" unique_key="unique_key_id" foreign-key="foreign_key_name" /> a. name: nombre de la propiedad. b. column (opcional): nombre de la columna de clave foránea. También puede ser especificado a través de etiquetas <column>. c. class (opcional): nombre de la clase asociada. d. cascade (opcional): operaciones que deben ejecutarse en cascada desde el padre al objeto asociado. e. fetch (opcional – select por defecto): elige entre búsqueda mediante outer- join o select secuencial. f. update (opcional – true por defecto): las columnas mapeadas deben incluirse en las sentencias UPDATE. g. insert (opcional – true por defecto): las columnas mapeadas deben incluirse en las sentencias INSERT. [53]
  • 54. HIBERNATE h. property-ref (opcional): nombre de la propiedad de la clase asociada relacionada con esta foreign key. Si no se especifica se utiliza la clave de la clase asociada. i. access (opcional – property por defecto): estrategia utilizada para acceder a la propiedad. j. unique (opcional): restricción unique para la clave foránea. k. not-null (opcional): restricción not-null para la clave foránea. l. optimistic-lock (opcional – true por defecto): las actualizaciones de esta propiedad requieren la adquisición del bloqueo optimista. m. lazy (optional – proxy por defecto): indica si esta propiedad debe ser buscada de forma perezosa cuando la instancia se accede por vez primera. n. not-found (opcional – exception por defecto): cómo se tratan las claves foráneas que referencian a filas inexistentes. o. entity-name (opcional): nombre de entidad de la clase asociada. p. formula (opcional): expresión SQL que define el valor de una propiedad calculada. 8. one-to-one <one-to-one name="propertyName" (a) class="ClassName" (b) cascade="cascade_style" (c) constrained="true|false" (d) fetch="join|select" (e) property-ref="propertyNameFromAssociatedClass" (f) access="field|property|ClassName" (g) formula="any SQL expression" (h) lazy="proxy|no-proxy|false" (i) entity-name="EntityName" (j) node="element-name|@attribute-name|element/@attribute|." embed-xml="true|false" foreign-key="foreign_key_name" /> a. name: nombre de la propiedad. b. class (opcional): nombre de la clase asociada. [54]
  • 55. HIBERNATE c. cascade (opcional): operaciones que deben ejecutarse en cascada desde el padre al objeto asociado. d. constrained (opcional): una clave foránea de la clave primaria de la tabla mapeada referencia a la tabla de la clase asociada. e. fetch (opcional – select por defecto): elige entre búsqueda mediante outer- join o select secuencial. f. property-ref (opcional): nombre de la propiedad de la clase asociada relacionada con esta foreign key. Si no se especifica se utiliza la clave de la clase asociada. g. access (opcional – property por defecto): estrategia utilizada para acceder a la propiedad. h. formula (opcional): expresión SQL que define el valor de una propiedad calculada. i. lazy (optional – proxy por defecto): indica si esta propiedad debe ser buscada de forma perezosa cuando la instancia se accede por vez primera. j. entity-name (opcional): nombre de entidad de la clase asociada. 9. set: las relaciones inversas normalmente se modelan a través de un conjunto (set), pero existen otros elementos que se pueden usar como list, map, bag, array o primitive-array. [55]
  • 56. HIBERNATE <set name="propertyName" (a) table="table_name" (b) schema="schema_name" (c) lazy="true|extra|false" (d) inverse="true|false" (e) cascade="all|none|save-update|delete|all-delete-orphan|delete-orphan" (f) sort="unsorted|natural|comparatorClass" (g) order-by="column_name asc|desc" (h) where="arbitrary sql where condition" (i) fetch="join|select|subselect" (j) batch-size="N" (k) access="field|property|ClassName" (l) optimistic-lock="true|false" (m) mutable="true|false" (n) node="element-name|." embed-xml="true|false" > <key .... /> (o) <map-key .... /> <element .... /> </map> a. name: nombre de la propiedad. b. table (opcional – nombre de la propiedad por defecto): nombre de la tabla de la colección (no se usa para one-to-many). c. schema (opcional): nombre del esquema para sobreescribir el esquema definido en el elemento raíz. d. lazy (opcional – true por defecto). e. inverse (opcional – false por defecto): indica el lado inverso en una asociación bidireccional. f. cascade (opcional - none por defecto): permite operaciones en cascada sobre los elementos hijos. g. sort (opcional): especifica una colección ordenada mediante orden natural o especificando una clase comparadora. [56]
  • 57. HIBERNATE h. order-by (opcional): solo en JDK 1.4, especifica un nombre de columna que define el orden de iteración. i. where (opcional): condición WHERE a utilizar cuando se recuperan o eliminan objetos de la colección. j. fetch (opcional – select por defecto): elige entre búsqueda mediante outer- join o select secuencial. k. batch-size (opcional – 1 por defecto): tamaño batch para la búsqueda de instancias de esta clase por campo clave. l. access (opcional – property por defecto): estrategia utilizada para acceder a la propiedad. m. optimistic-lock (opcional – true por defecto): las actualizaciones del estado de la colección requieren la adquisición del bloqueo optimista. n. mutable (opcional – true por defecto): los elementos de la colección nunca cambian. o. key: dentro de la etiqueta set indica la clave foránea de la colección: <key column="columnname" (i) on-delete="noaction|cascade" (ii) property-ref="propertyName" (iii) not-null="true|false" (iv) update="true|false" (v) unique="true|false" (vi) /> i. column (opcional): nombre de la columna que actúa como clave foránea. También puede especificarse a través de elementos <column>. ii. on-delete (opcional – noaction por defecto): la clave foránea tiene activado el borrado en cascada en la base de datos. iii. property-ref (opcional): la clave foránea se refiere a columnas que no son la clave primaria de la tabla original. iv. not-null (opcional): las claves foráneas no se pueden establecer como null. [57]
  • 58. HIBERNATE v. update (opcional): las claves foráneas no se pueden actualizar. vi. unique (opcional): la clave foránea debería tener una restricción unique. p. one-to-many: indica <one-to-many class="ClassName" (i) not-found="ignore|exception" (ii) entity-name="EntityName" (iii) node="element-name" embed-xml="true|false" /> i. class: nombre de la clase asociada. ii. not-found (opcional – exception por defecto): cómo se tratan las claves foráneas que referencian a filas inexistentes. iii. entity-name (opcional): nombre de entidad de la clase asociada. 3.4.EL INTERFAZ SESSION El interfaz Session es la principal vía de interacción entre la aplicación Java e Hibernate. Representa a la sesión actual, donde se producen transacciones para la interacción con la Base de datos, efectuando operaciones de lectura, creación, modificación y eliminación de instancias de clases mapeadas. Las instancias de tales clases se pueden encontrar en tres estados posibles: transient: no es persistente, no está asociada a ninguna sesión. Se pueden convertir en persistent invocando a los métodos save, persist o saveOrUpdate. Se encuentra en la aplicación pero no en la Base de datos. persistent: asociado a una única sesión. Se encuentra en la aplicación y en la Base de datos. [58]
  • 59. HIBERNATE detached: persistente previamente, no asociado con ninguna sesión. Se encuentra en la Base de datos, pero no se ha recuperado desde la aplicación. En la siguiente ilustración aparecen estos estados, y cuáles son los métodos que provocan la transición de uno a otro. Para poder operar con una sesión es necesario obtener una instancia de la misma y comenzar una transacción. Cualquier operación sobre dicha instancia debe contenerse dentro de una transacción. Si se produce una excepción dentro de la transacción, ésta debe ser cancelada (rollback), si no hay que confirmarla para hacer persistentes los cambios (commit): [59]
  • 60. HIBERNATE //Obtener la sesión actual Session session = HibernateUtil.getSessionFactory().getCurrentSession(); try{ //Comenzar la transacción session.beginTransaction(); //Operaciones con session … }catch (Exception ex){ //Deshacer transacción session.getTransaction().rollback(); }finally{ //Confirmar transacción session.getTransaction().commit(); } Los métodos que se invocan sobre la instancia de Session producen operaciones sobre la Base de datos a través de sentencias SQL, generadas en el dialecto concreto configurado en hibernate.cfg. De esta forma, las siguientes sentencias se producen para los métodos enumerados anteriormente: INSERT: save, persist, saveOrUpdate, replicate. UPDATE: update, merge, saveOrUpdate, replicate. DELETE: delete. A continuación se exponen algunos métodos de la clase Session utilizados habitualmente. Para mayor información se puede acceder a la API de Hibernate: http://www.hibernate.org/hib_docs/v3/api/ [60]