viernes, 1 de mayo de 2009

HIbernate - Parte 1: Persistiendo Objetos Simples usando Mapeos en XML

En la mayoría de las aplicaciones empresariales, si no es que en todas, una parte muy importante es el almacenamiento de datos de forma que estos datos puedan sobrevivir más allá del tiempo que nuestra aplicación está encendida (ya sea en una aplicación standalone o en una aplicación web).

El almacén de datos más común son las bases de datos relacionales. La naturaleza de estas bases hace que no sea tan fácil usarlas en el almacenamiento de datos en aplicaciones orientadas a objetos (por las diferencias entre el modelo de datos de objetos y el modelo de datos relacionales), ya que para guardar un objeto debemos extraer cada una de sus propiedades que queremos persistir y armar con ellos una sentencia INSERT de SQL. De la misma forma, cuando queremos recuperar los datos de un objeto, debemos usar una sentencia SELECT de SQL y después extraer el valor de cada una de las columnas recuperadas y llenar así nuestro objeto.

Esto puede no parecer un problema en aplicaciones pequeñas, pero cuando comenzamos a tener muchos objetos que debemos guardar se vuelve algo muy pesado y engorroso, además de que consume mucho de nuestro tiempo que podríamos dedicar a mejorar la lógica de la aplicación, o a realizar pruebas de la misma.

Esto se hizo de esta manera durante muchos años, hasta que comenzaron a surgir las soluciones de Mapeo Objeto/Relacional (ORM por sus siglas en inglés). El mapeo objeto/relacional se refiere a una técnica de mapear representaciones de datos de un modelo de objetos a un modelo de datos relacionales con un esquema basado en SQL.

Hibernate, como la definen sus autores, es una herramienta de mapeo objeto/relacional para ambientes Java. Además no solo se encarga del mapeo de clases Java a tablas de la base de datos (y de regreso), sino que también maneja los queries y recuperación de datos, lo que puede reducir de forma significativa el tiempo de desarrollo que de otra forma gastaríamos manejando los datos de forma manual con SQL y JDBC, encargándose de esta forma de alrededor del 95% de las tareas comunes relacionadas con la persistencia de datos, manejando todos los problemas relativos con la base de datos particular con la que estemos trabajando, de forma transparente para nosotros como desarrolladores. Entonces, si cambiamos el manejador de base de datos no será necesario que modifiquemos todo el SQL que ya teníamos para adaptarse al SQL que maneja la nueva base de datos. Solo será necesario modificar una línea en un archivo de configuración de Hibernate, y este se encargará del resto.

En esta serie de tutoriales veremos cómo usar Hibernate para realizar las tareas más comunes cuando trabajamos con bases de datos. Existen dos formas de hacer los mapeos en Hibernate, la primera es a través de archivos de mapeo en XML, que es la forma que veremos en este primer tutorial. La otra forma es usando anotaciones, que dejaremos para la segunda. Así que comencemos.

Para los tutoriales usaremos MySQL 5.1 como base de datos. También deben bajar el conector para Java versión 5.1.7.

Creamos una base de datos llamada "pruebahibernate". No se preocupen por crear alguna tabla, ya que haremos que sea el propio Hibernate el que las genere. Ahora comencemos con nuestra aplicación.

Lo primero que haremos es crear una biblioteca de NetBeans con los jars básicos de Hibernate, de esta forma cada vez que queramos usar Hibernate en un proyecto solo tendremos que agregar esta biblioteca. En realidad no crearemos esta biblioteca desde cero, ya que NetBeans ya tiene una biblioteca de Hibernate 3.2.5, solo actualizaremos la biblioteca con la última versión de Hibernate, la 3.3.1 GA. Así que descargamos la última versión del core de Hibernate desde la página de descarga de Hibernate.

Una vez que descarguemos y descomprimamos el archivo correspondiente veremos que en la raíz hay dos jars de Hibernate: "hibernate3.jar" y "hibernate-testing.jar". "hibernate3.jar" contiene las clases principales para el uso de Hibernate. Existen varias clases de soporte que son usadas por Hibernate para su funcionamiento normal. Algunas son opcionales y otras son requeridas. Afortunadamente estas se encuentran separadas en el mismo archivo que hemos descargado. Las clases obligatorias, que son las que nos interesan en este caso, se encuentran en el directorio "lib\required".

Bien, entonces para actualizar la biblioteca abrimos el NetBeans y nos dirigimos al menú "Tools -> Libraries":



En la ventana que se abre buscamos la biblioteca "Hibernate" y la seleccionamos. Con esto se mostrarán los archivos que la conforman. Seleccionamos todos los archivos y presionamos el botón "Remove" para eliminarlos de la biblioteca.



Una vez eliminados los archivos presionamos el botón "Add JAR/Folder..." para agregar los nuevos archivos:



Agregamos a la biblioteca los siguientes archivos:

  • hibernate3.jar

y del directorio de jars requeridos:

  • antlr-2.7.6.jar
  • commons-collections-3.1.jar
  • dom4j-1.6.1.jar
  • javassist-3.4.GA.jar
  • jta-1.1.jar

O sea, casi todos los archivos requeridos. Estamos excluyendo el archivo "slf4j-api-1.5.2.jar" porque si lo incluimos solo, se lanza una excepción. Lo que ocurre es que slf4j es una fachada para el logging, o bitácora de la aplicación (similar a "commons-logging" que estuvimos usando el los tutoriales de JasperReports). Esto significa que podemos usar el framework de logging que queramos (en teoría). Sin embargo en la distribución de Hibernate no se incluye ningún jar con una clase que implemente dicha fachada, por lo que debemos bajar uno nosotros mismos.

Podemos hacer dos cosas, la primer es agregar el archivo "slf4j-api-1.5.2.jar" que viene con Hibernate a nuestra biblioteca y el zip con la versión correspontiente de slf4j. De él extraemos "slf4j-simple-1.5.2.jar" (o el archivo que se ajuste al framework de logging que estemos usando) y lo incluimos en la biblioteca.

Lo otro que podemos hacer es, aprovechando que ya estamos bajando jars, descargar la última versión de slf4j de aquí (actualmente es la 1.5.6) y aprovechar para agregar los archivos "slf4j-api-1.5.6.jar" y "slf4j-simple-1.5.6.jar" a nuestra biblioteca. Yo haré esto último.

Una vez seleccionados estos archivos la biblioteca de Hibernate debe verse así:



Presionamos el botón "OK" y nuestra biblioteca ya estará actualizada.

Ahora creamos un nuevo proyecto de NetBeans (menú "File -> New Project... -> Java -> Java Application"). Le damos un nombre y una ubicación al proyecto y nos aseguramos de que las opciones "Create Main Class" y "Set as Main Project" estén habilitadas. Presionamos el botón "Finish" y veremos aparecer en el editor nuestra clase "Main".

Agregamos la biblioteca de "Hibernate", que creamos hace unos momentos, a nuestro proyecto. Hacemos clic derecho en el nodo "Libraries" del proyecto. En el menú contextual que se abre seleccionamos la opción "Add Library...":



En la ventana que se abre seleccionamos la biblioteca "Hibernate":



Presionamos el botón "Add Library" para que la biblioteca se agregue a nuestro proyecto. Aprovechamos también para agregar el conector de MySQL. Debemos tener los siguientes archivos en nuestro proyecto:



El siguiente paso es crear una clase cuyas instancias serán almacenadas como fila de una tabla en base de datos. Este tipo de objetos son llamados "Entidades". Para este ejemplo crearemos una pequeña y básica agenda, así que las entidades serán objetos de la clase "Contacto".

Los atributos que tendrá esta serán un nombre, un correo, y un número telefónico. Además, por regla, necesitamos un atributo que funcione como identificador para cada una de las entidades.

En este caso he hecho que la clase implementa la interface "java.io.Serializable", esto no es obligatorio pero es una buena práctica.

La clase "Contacto" queda de la siguiente forma:

public class Contacto implements Serializable
{
    private long id;
    private String nombre;
    private String email;
    private String telefono;

    public Contacto()
    {
    }

    public Contacto(String nombre, String email, String telefono)
    {
        this.nombre = nombre;
        this.email = email;
        this.telefono = telefono;
    }

    public String getEmail()
    {
        return email;
    }

    public void setEmail(String email)
    {
        this.email = email;
    }

    public long getId()
    {
        return id;
    }

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

    public String getNombre()
    {
        return nombre;
    }

    public void setNombre(String nombre)
    {
        this.nombre = nombre;
    }

    public String getTelefono()
    {
        return telefono;
    }

    public void setTelefono(String telefono)
    {
        this.telefono = telefono;
    }
}


La clase "Contacto" usa la convención de nombres JavaBeans para los getters y setters y visibilidad privada para los atributos. Este también es un diseño recomendado pero no obligatorio. Hibernate puede acceder a los campos o atributos de las entidades directamente.

El constructor sin argumentos si es obligatorio ya que Hibernate creará instancias de esta clase usando reflexión cuando recupere las entidades de la base de datos. Este constructor puede ser privado (si es que no quieren permitir que alguien más lo utilice), pero usualmente el nivel de acceso más restrictivo que usaremos es el de paquete (el default), ya que esto hace más eficiente la creación de los objetos.

La propiedad "id" mantendrá, como dije antes, un valor único que identificará a cada una de las instancias de "Contacto". Todas las clases de entidades persistentes deben tener una propiedad que sirva como identificador si queremos usar el conjunto completo de funcionalidades que nos ofrece Hibernate (y que veremos a lo largo de esta serie de tutoriales). De todas formas, la mayoría de las aplicaciones necesitan poder distinguir objetos de la misma clase mediante algún tipo de identificador. Usualmente no manipulamos directamente este identificador (dejamos que sea la base de datos quien lo genere, cuando la entidad sea guardada, y Hibernate quien lo asigne al objeto), por lo tanto el setter del "id" es privado (fíjense cómo lo he puesto en la clase "Contacto").

Hibernate puede acceder a los campos private directamente, así que no debemos preocuparnos por el hecho de que el identificador no pudiera ser establecido.

El siguiente paso es crear el archivo de mapeo. Si recuerdan, anteriormente dije que Hibernate es una herramienta de mapeos Objeto/Relacional, o sea que mapea los atributos de los objetos con las columnas de una tabla de una base de datos relacional. También dije que hay dos formas de hacerlo: mediante un archivo de mapeo en XML y mediante anotaciones y que en esta ocasión veríamos solo como usar los archivos de mapeo.

Crearemos un nuevo paquete que contendrá los archivos de mapeo, no es obligatorio tener los archivos de mapeo en un paquete separado ya que más adelante indicaremos donde se encuentra cada uno de los archivos, pero nos ayudará a mantener un poco de orden en nuestro proyecto. Hacemos clic derecho sobre el nodo "Source Packages" del proyecto para mostrar un menú contextual. De ese menú seleccionamos la opción "New -> Java Package..":



Nombramos a este paquete como "mapeos" y presionamos el botón "Finish" para agregar el nuevo paquete.

Ahora creamos un nuevo archivo XML que contendrá el mapeo de la clase "Contacto" con la tabla "CONTACTOS" de la base de datos. Por convención la extensión de estos archivos es ".hbm.xml" y tiene el mismo nombre de la entidad que está mapeando (aunque eso tampoco es necesario ya que podemos mapear más de una clase o entidad dentro del mismo archivo).

Hacemos clic derecho sobre el paquete que acabamos de crear. En el menú contextual que se abre seleccionamos la opción "New -> XML Document". Si no se muestra está opción seleccionamos "Other..." y en la ventana que se abre seleccionamos "XML -> XML Document":



Le damos al archivo el nombre "Contacto.hbm" (el asistente se encargará de agregar de forma automática el ".xml" al final):



Presionamos el botón "Next >" y se nos preguntará qué tipo de documento queremos crear: solo un documento XML bien formado, un documento regido por un DTD, o un documento regido por un Schema XML. Aunque el documento de mapeo está regido por un DTD nosotros elegiremos crear un documento XML bien formado ("Well-formed Document") ya que es más fácil simplemente pegarlo en el archivo que se creará que indicar mediante el asistente dónde se encuentra este archivo. Presionamos el botón "Finish" para que se nos muestre en el editor el nuevo archivo XML, el cual debe verse más o menos así:



Modificaremos este archivo. Eliminamos todo el contenido del archivo y lo reemplazamos por este:

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
        "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
        "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">

<hibernate-mapping>
    
</hibernate-mapping>


Teniendo esta declaración, la cual indica el DTD que se usa para validar el archivo, el IDE nos ayudará a autocompletar las etiquetas y a asegurarnos que el archivo sea válido.

El elemento "<hibernate-mapping>" es el nodo raíz del documento y, por lo tanto, el resto de los elementos irán entre estas dos etiquetas.

El elemento con el que indicamos qué clase es la que estamos mapeando es el elemento "<class>" este elemento tiene los atributos "name" y "table" que nos permiten indicar el nombre completo de la clase y la tabla con la que será mapeada, respectivamente:

<hibernate-mapping>
    <class name="hibernatenormal.Contacto" table="CONTACTOS">

    </class>
</hibernate-mapping>


Con esto indicamos que las entidades de la clase "Contacto" serán almacenadas en la tabla "CONTACTOS". Ahora debemos indicar cuál de los elementos de la clase entidad es el identificador. Este identificador será mapeado con la llave primaria de la tabla, además como nosotros no manejaremos el valor del identificador, le indicamos a Hibernate cómo queremos que este valor sea generado (la estrategia de generación). Para esto usamos el elemento "<id>", indicando el nombre del atributo de la clase entidad que representa el identificador (que en este caso también se llama "id" ^-^). Opcionalmente en este elemento (como en el resto de los elementos de mapeo de propiedades) podemos indicar con qué columna queremos que se mapee usando el atributo "column":

<hibernate-mapping>
    <class name="hibernatenormal.Contacto" table="CONTACTOS">
        <id name="id" column="ID">
            <generator class="identity" />
        </id>
    </class>
</hibernate-mapping>


El elemento "<generator>" es el que nos permite indicar la estrategia de generación del identificador usando su atributo "class". Existen varias estrategias que están explicadas en esta página, pero las que usaremos más frecuentemente son "identity" (con la que Hibernate se encarga de generar el query necesario para que el nuevo identificador sea igual a el último identificador + 1) y "native" (con el que se usa la estrategia por default del manejador que estemos utilizando (dialecto)).

Para terminar con el mapeo incluimos las declaraciones para el resto de las propiedades persistentes (las que queremos que sean almacenadas) de la clase entidad ("nombre", "email", y "telefono") usando el elemento "<property>" en el cual indicamos el nombre de la propiedad como aparece en la clase entidad y, opcionalmente, el tipo de la propiedad y la columna con la que será mapeada usando los atributos "type" y "column" respectivamente:

<hibernate-mapping>
    <class name="hibernatenormal.Contacto" table="CONTACTOS">
        <id name="id" column="ID">
            <generator class="identity" />
        </id>
        <property name="nombre" type="string" column="NOMBRE" />
        <property name="email" />
        <property name="telefono" />
    </class>
</hibernate-mapping>


El archivo "Contacto.hbm.xml" final debe verse así:



¿Qué ocurre si no indicamos el tipo de la propiedad? En ese caso Hibernate utiliza nuevamente reflexión en nuestra clase para determinar el tipo del atributo y así elegir el tipo más adecuado para la columna de la tabla (en caso de que dejemos que Hibernate genere las tablas).

¿Qué ocurre si no indicamos el nombre de la columna con la que mapea una propiedad? Esto depende de si Hibernate está generando las tablas de la base de datos o las hemos generado nosotros mismos. Si es Hibernate quien está generando las tablas no hay problema, simplemente dará a la columna correspondiente el mismos nombre de la propiedad. Por ejemplo, para la propiedad "email" creará una columna "email". Sin embargo, si nosotros hemos creado las tablas hay un riesgo potencial de un error. Hibernate buscará en las consultas una columna con el mismo nombre de la propiedad, pero si hemos usado un nombre distinto, por ejemplo en vez de "email" hemos llamado a la columna "E_MAIL" ocurrirá una excepción indicando que no se ha encontrado la columna "email", así que en ese caso debemos tener cuidado de indicar el nombre de las columnas como están en la base de datos.

Bien, después de esta breve explicación podemos proseguir.

Ya que hemos configurado el mapeo de nuestra clase entidad debemos configurar Hibernate. Hibernate está en la capa de nuestra aplicación que se conecta a la base de datos (la capa de persistencia), así que necesita información de la conexión. La conexión se hace a través de un pool de conexiones JDBC que también debemos configurar. La distribución de Hibernate contiene muchos pools de conexiones JDBC Open Source, como por ejemplo C3P0, pero en esta ocasión usaremos el pool de conexiones que Hibernate trae integrado.

La configuración de Hibernate puede hacerse en tres lugares:

  • Un archivo de propiedades llamado "hibernate.properties".
  • Un archivo XML llamado "hibernate.cfg.xml".
  • En código dentro de la misma aplicación.

En realidad los archivos pueden tener cualquier nombre, pero Hibernate buscará por default los archivos con los nombres que he mencionado, en una ubicación predeterminada (la raíz del classpath de la aplicación). Si queremos usar archivos con otros nombres deberemos especificarlo en el código.

La mayoría, por lo que he podido ver en Internet, preferimos usar el archivo XML ya que, entre otras cosas, los IDEs nos ayudan a su creación y configuración gracias a que está regido por un DTD. Así que crearemos este archivo en nuestro proyecto. Hacemos clic derecho en el nodo "Source Packages" del proyecto. En el menú contextual que se abre seleccionamos "New -> XML Document...":



Nombramos al archivo "hibernate.cfg", el IDE se encargará de colocarle la extensión ".xml". Ubicamos el archivo en el directorio "src":



Con esto lograremos que el archivo quede en la raíz del classpath de la aplicación, también conocido como el paquete default. Presionamos el botón "Next >" y en la pantalla siguiente indicamos que queremos crear un documento XML bien formado (como en el caso anterior). Presionamos el botón "Finish " para generar el archivo. Si nos fijamos en el archivo generado, este debe encontrarse en un paquete llamado "<default package>":



Borramos todo el contenido del archivo generado y colocamos las siguientes líneas:

<?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>
</hibernate-configuration>


El DTD nos ayudará para que el IDE autocomplete las etiquetas.

Como podemos ver, el elemento raíz del archivo de configuración es "<hibernate-configuration>" y, por lo tanto, todos los elementos los colocaremos entre estas dos etiquetas.

Lo primero que debemos hacer es configurar un "session-factory", que básicamente es lo que le dice a Hibernate cómo conectarse y manejar la conexión a la base de datos. Podemos tener más de un "session-factory" en el archivo de configuración (por si quisiéramos conectarnos a más de una base de datos), pero por lo regular solo ponemos uno:

<hibernate-configuration>
    <session-factory>
        
    </session-factory>
</hibernate-configuration>


Lo siguiente es configurar la conexión a nuestra base de datos. En este archivo se configuran los parámetros básicos y típicos para una conexión (la URL, nombre de usuario, contraseña, driver, etc.). Cada uno de estos parámetros se configura dentro de una etiqueta "<property>" (al igual que casi todos los elementos del archivo de configuración). Como dije antes, usaré una base de datos MySQL para este ejemplo, así que mi configuración queda de la siguiente forma:

<property name="connection.driver_class">com.mysql.jdbc.Driver</property>
<property name="connection.url">jdbc:mysql://localhost/pruebahibernate</property>
<property name="connection.username">usuario</property>
<property name="connection.password">password</property>


Después, configuramos el pool de conexiones de Hibernate. En este caso como es un ejemplo muy simple, solo nos interesa tener una conexión en el pool, por lo que colocamos la propiedad "connection.pool_size" con un valor de "1":

<property name="connection.pool_size">1</property>


El siguiente paso es muy importante. Debemos indicar el "dialecto" que usará Hibernate para comunicarse con la base de datos. Este dialecto es la variante de SQL que usa la base de datos para ejecutar queries. Indicamos el dialecto con el fully qualified class name, o el nombre completo de la clase incluyendo el paquete. En el caso de MySQL 5 usamos "org.hibernate.dialect.MySQL5Dialect". En esta página pueden encontrar una lista más o menos completa de los dialectos soportados por Hibernate, pero siempre es mejor revisar la documentación de la versión que estén usando para estar seguros:

<property name="dialect">org.hibernate.dialect.MySQL5Dialect</property>


Otras dos propiedades importantes que podemos configurar son: "show_sql" que indica si queremos que las consultas SQL generadas sean mostradas en el stdout (normalmente la consola), y "hbm2ddl.auto", que indica si queremos que se genere automáticamente el esquema de la base de datos (las tablas). "show_sql" puede tomar valores de "true" o "false", yo lo colocaré en "true" (lo que puede ser bueno mientras estamos en etapas de desarrollo o pruebas, pero querrán cambiar su valor cuando su aplicación pase a producción). Por otro lado "hbm2ddl.auto" puede tomar los valores, segun la documentación oficial(falta "none"), de "validate", "update", "create", y "create-drop" (aunque no todos los valores funcionan para todas las bases de datos). Yo los colocaré de la siguiente forma:

<property name="show_sql">true</property> 
<property name="hbm2ddl.auto">create-drop</property>


Con el valor "create-drop" hacemos que cada vez que se ejecute la aplicación Hibernate elimine las tablas de la base de datos y las vuelva a crear. Para terminar con este archivo de configuración, debemos indicar dónde se encuentra cada uno de los archivos de mapeo que hemos creado, usando el elemento "<mapping>". En nuestro caso solo hemos creado un archivo de mapeo, pero debemos colocar un elemento "<mapping>" por cada uno de los archivos que hayamos creado:

<mapping resource="mapeos/Contacto.hbm.xml"/>


En el elemento "resource" debemos colocar la ubicación de los archivos de mapeo dentro de la estructura de paquetes de la aplicación. El archivo de configuración "hibernate.cfg.xml" final debe verse así:

<?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>
  
    <!-- parametros para la conexion a la base de datos -->
    <property name="connection.driver_class">com.mysql.jdbc.Driver</property>
    <property name="connection.url">jdbc:mysql://localhost/pruebahibernate</property>
    <property name="connection.username">usuario</property>
    <property name="connection.password">password</property>
    
    <!-- Configuracion del pool interno -->
    <property name="connection.pool_size">1</property>
    
    <!-- Dialecto de la base de datos -->
    <property name="dialect">org.hibernate.dialect.MySQL5Dialect</property>
    
    <!-- Otras propiedades importantes -->
    <property name="show_sql">true</property>
    <property name="hbm2ddl.auto">create-drop</property>
    
    <!-- Archivos de mapeo -->
    <mapping resource="mapeos/Contacto.hbm.xml"/>
  </session-factory>
</hibernate-configuration>




Esta es toda la configuración que debemos hacer. Ahora veremos el código necesario para guardar y recuperar objetos "Contacto" de la base de datos.

Lo primero que haremos es crear una clase ayudante o de utilidad llamada "HibernateUtil", que se hará cargo de inicializar y hacer el acceso al "org.hibernate.SessionFactory" (el objeto encargado de gestionar las sesiones de conexión a la base de datos que configuramos en el archivo "hibernate.cfg.xml") más conveniente.

Dentro de esta clase declaramos un atributo static de tipo "SessionFactory", así nos aseguraremos de que solo existe una instancia en la aplicación. Además lo declararemos como final para que la referencia no pueda ser cambiada después de que la hayamos asignado.

private static final SessionFactory sessionFactory;


Después usamos un bloque de inicialización estático para inicializar esta variable en el momento en el que la clase sea cargada en la JVM.

Para realizar esta inicialización lo primero que se necesita es una instancia de la clase "org.hibernate.cfg.Configuration" que permite a la aplicación especificar las propiedades y documentos de mapeo que se usarán (es aquí donde indicamos todo si no queremos usar un archivo XML o de propiedades). Si usamos el método "configure()" que no recibe parámetros entonces Hibernate busca el archivo "hibernate.cfg.xml" que creamos anteriormente. Una vez que tenemos este objeto, entonces podemos inicializar la instancia de "SessionFactory" con su método "buildSessionFactory()". Además como este proceso puede lanzar "org.hibernate.HibernateException" (que extiende de "RuntimeException") la cachamos y lanzamos como un "ExceptionInInitializarError" (que es lo único que puede lanzarse desde un bloque de inicialización). El bloque de inicialización queda de la siguiente forma:

static
{
    try 
    { 
        sessionFactory = new Configuration().configure().buildSessionFactory();
    } catch (HibernateException he) 
    { 
        System.err.println("Ocurrió un error en la inicialización de la SessionFactory: " + he); 
        throw new ExceptionInInitializerError(he); 
    } 
}


Finalmente creamos un método static llamado "getSessionFactory()" para recuperar la instancia de la "SessionFactory":

public static SessionFactory getSessionFactory()
{ 
    return sessionFactory;
} 


La clase "HibernateUtil" queda de la siguiente forma:

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

public class HibernateUtil
{  
    private static final SessionFactory sessionFactory;   

    static 
    { 
        try 
        { 
            sessionFactory = new Configuration().configure().buildSessionFactory(); 
        } catch (HibernateException he) 
        { 
           System.err.println("Ocurrió un error en la inicialización de la SessionFactory: " + he); 
           throw new ExceptionInInitializerError(he); 
        } 
    }  

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




Bien ha llegado el momento, ahora escribiremos una clase DAO (no seguiremos el patrón al pie de la letra, es solo para mostrar cómo trabajar con Hibernate) que nos permitirá realizar operaciones de base de datos.

Creamos una clase llamada "ContactosDAO" y agregamos dos atributos, uno llamado "sesion" de tipo "org.hibernate.Session", y otro llamado "tx" de tipo "org.hibernate.Transaction".

private Session sesion;
private Transaction tx;


Estos atributos nos servirán para mantener la referencia a la sesión a base de datos, y a la transacción actual, respectivamente. Ahora agregaremos dos métodos de utilidad. El primero nos ayudará a iniciar una sesión y una transacción en la base de datos. Llamaremos a este método "iniciaOperacion", y la implementación es la siguiente:

private void iniciaOperacion() throws HibernateException
{
    sesion = HibernateUtil.getSessionFactory().openSession();
    tx = sesion.beginTransaction();
}


En el método anterior obtenemos una referencia a "SessionFactory" usando nuestra clase de utilidad "HibernateUtil". Una vez que tenemos la "SessionFactory" creamos una conexión a la base de datos e iniciamos una nueva sesión con el método "openSession()". Una vez teniendo la sesión iniciamos una nueva transacción y obtenemos una referencia a ella con "beginTransaction()".

Ahora el segundo método de utilidad (llamado "manejaExcepcion") nos ayudará a manejar las cosas en caso de que ocurra una excepción. Si esto pasa queremos que la transacción que estamos ejecutando se deshaga y se relance la excepción (o podríamos lanzar una propia). Por lo que el método queda así:

private void manejaExcepcion(HibernateException he) throws HibernateException
{
    tx.rollback();
    throw new HibernateException("Ocurrió un error en la capa de acceso a datos", he);
}


Ahora crearemos los métodos que nos permitirán realizar las tareas de persistencia de una entidad "Contacto", conocidas en lenguaje de base de datos como CRUD: guardarla, actualizarla, eliminarla, buscar un entidad "Contacto" y obtener todas los contactos que existen en la base de datos, así que comencemos.

Afortunadamente Hibernate hace que esto sea fácil ya que proporciona métodos para cada una de estas tareas. Primero veamos como guardar un objeto "Contacto". Para esto Hibernate proporciona el método "save" en el objeto de tipo "org.hibernate.Session", que se encarga de generar el "INSERT" apropiado para la entidad que estamos tratando de guardar. El método "guardaContacto" queda de la siguiente forma:

public long guardaContacto(Contacto contacto)
{ 
    long id = 0;  

    try 
    { 
        iniciaOperacion(); 
        id = (Long)sesion.save(contacto); 
        tx.commit(); 
    }catch(HibernateException he) 
    { 
        manejaExcepcion(he);
        throw he; 
    }finally 
    { 
        sesion.close(); 
    }  
    return id; 
}


Regresamos el "id" generado al guardar el "Contacto" solo por si queremos usarlo más adelante en el proceso (como lo haremos nosotros), o si queremos mostrarle al usuario, por alguna razón, el identificador del "Contacto".

Ahora veremos cómo actualizar un "Contacto". Para eso usamos el método "update" del objeto "sesion" en nuestro método "actualizaContacto":

public void actualizaContacto(Contacto contacto) throws HibernateException 
{ 
    try 
    { 
        iniciaOperacion(); 
        sesion.update(contacto); 
        tx.commit(); 
    }catch (HibernateException he) 
    { 
        manejaExcepcion(he); 
        throw he; 
    }finally 
    { 
        sesion.close(); 
    } 
}


Como podemos ver, el método para actualizar es muy similar al método para guardar la entidad. Lo mismo ocurre con el método para eliminarla, "eliminaContacto":

public void eliminaContacto(Contacto contacto) throws HibernateException 
{ 
    try 
    { 
        iniciaOperacion(); 
        sesion.delete(contacto); 
        tx.commit(); 
    } catch (HibernateException he) 
    { 
        manejaExcepcion(he); 
        throw he; 
    }finally 
    { 
        sesion.close(); 
    } 
}


Ahora veremos unos métodos un poco más interesantes.

Cuando queremos buscar una entidad podemos usar varios criterios. La forma más fácil es buscar una entidad particular usando su "id". La clase "org.hibernate.Session" proporciona dos métodos para esto: "load" y "get". Los dos hacen prácticamente lo mismo: en base al identificador y tipo de la entidad recuperan la entidad indicada, con la diferencia de que "load" lanza una excepción en caso de que la entidad indicada no sea encontrada en la base de datos, mientras que "get" simplemente regresa "null". Pueden usar el que prefieran, en lo personal me gusta más "get", así que lo usaré para el método "obtenContacto":

public Contacto obtenContacto(long idContacto) throws HibernateException
{ 
    Contacto contacto = null;  

    try 
    { 
        iniciaOperacion(); 
        contacto = (Contacto) sesion.get(Contacto.class, idContacto); 
    } finally 
    { 
        sesion.close(); 
    }  
    return contacto; 
}


Finalmente veremos el método "obtenListaContactos" que recupera todos los Contactos que estén guardados en la base de datos. Como en este caso regresaremos una lista de elementos deberemos crear una consulta. Cuando tenemos que crear una consulta con JDBC lo hacemos en SQL, sin embargo con Hibernate tenemos varias opciones:

  • Usar una query en SQL nativo.
  • Crear una query en HQL (Hibernate Query Language).
  • Crear una query usando Criteria que es un API para crear queries de una forma más "orientada a objetos".

Critera es, a mi parecer, la forma más fácil de crear las queries. Sin embargo, también en mi opinión, HQL es más poderosa y tenemos más control sobre lo que está ocurriendo, así que será esta forma la que usaremos.

Creando la consulta en HQL Hibernate la transformará al SQL apropiado para la base de datos que estemos usando. La consulta en realidad es muy simple: indicamos que queremos obtener datos (generar un "SELECT"), en este caso la clausula "SELECT" no es necesaria (aunque si existe) porque vamos a regresar todos los datos del objeto (podemos indicar solo unos cuantos atributos, eso es llamado proyección, pero se maneja de una forma distinta). Lo que si debemos indicar es de cuál clase queremos recuperar las instancias, por lo que necesitamos la clausula "FROM" y el nombre de la clase (recuerden que en base al nombre de la clase Hibernate sabrá en cuál tabla están almacenadas las entidades). Espero que esta explicación se haya entendido, se que es un poco enredado, pero quedará más claro con el ejemplo:

public List<Contacto> obtenListaContactos() throws HibernateException 
{ 
    List<Contacto> listaContactos = null;  
    
    try 
    { 
        iniciaOperacion(); 
        listaContactos = sesion.createQuery("from Contacto").list(); 
    }finally 
    { 
        sesion.close(); 
    }  

    return listaContactos; 
}


Eso es todo, nuestra consulta para recuperar todos los Contactos que tenemos en la base de datos solo debemos usar la clausula "FROM Contacto". Si quieren una referencia más amplia de HQL pueden encontrarla en el tutorial sobre HQL.

Bien, eso es todo. La clase "ContactosDAO" queda de la siguiente forma (omitiendo los imports):

public class ContactosDAO
{  
    private Session sesion; 
    private Transaction tx;  

    public long guardaContacto(Contacto contacto) throws HibernateException 
    { 
        long id = 0;  

        try 
        { 
            iniciaOperacion(); 
            id = (Long) sesion.save(contacto); 
            tx.commit(); 
        } catch (HibernateException he) 
        { 
            manejaExcepcion(he); 
            throw he; 
        } finally 
        { 
            sesion.close(); 
        }  

        return id; 
    }  

    public void actualizaContacto(Contacto contacto) throws HibernateException 
    { 
        try 
        { 
            iniciaOperacion(); 
            sesion.update(contacto); 
            tx.commit(); 
        } catch (HibernateException he) 
        { 
            manejaExcepcion(he); 
            throw he; 
        } finally 
        { 
            sesion.close(); 
        } 
    }  

    public void eliminaContacto(Contacto contacto) throws HibernateException 
    { 
        try 
        { 
            iniciaOperacion(); 
            sesion.delete(contacto); 
            tx.commit(); 
        } catch (HibernateException he) 
        { 
            manejaExcepcion(he); 
            throw he; 
        } finally 
        { 
            sesion.close(); 
        } 
    }  

    public Contacto obtenContacto(long idContacto) throws HibernateException 
    { 
        Contacto contacto = null;  
        try 
        { 
            iniciaOperacion(); 
            contacto = (Contacto) sesion.get(Contacto.class, idContacto); 
        } finally 
        { 
            sesion.close(); 
        }  

        return contacto; 
    }  

    public List<Contacto> obtenListaContactos() throws HibernateException 
    { 
        List<Contacto> listaContactos = null;  

        try 
        { 
            iniciaOperacion(); 
            listaContactos = sesion.createQuery("from Contacto").list(); 
        } finally 
        { 
            sesion.close(); 
        }  

        return listaContactos; 
    }  

    private void iniciaOperacion() throws HibernateException 
    { 
        sesion = HibernateUtil.getSessionFactory().openSession(); 
        tx = sesion.beginTransaction(); 
    }  

    private void manejaExcepcion(HibernateException he) throws HibernateException 
    { 
        tx.rollback(); 
        throw new HibernateException("Ocurrió un error en la capa de acceso a datos", he); 
    } 
}


Ahora, y para terminar el ejemplo, haremos uso de "ContactosDAO" para crear y recuperar algunas instancias de "Contacto". Creo que el código es muy claro así que no lo explicaré ^-^!. La clase "Main" queda de la siguiente forma:

public class Main
{ 
    public static void main(String[] args) 
    { 
        ContactosDAO contactosDAO = new ContactosDAO(); 
        Contacto contactoRecuperado = null;  
        long idAEliminar = 0;  

        //Creamos tes instancias de Contacto 
        Contacto contacto1 = new Contacto("Contacto 1", "contacto1@contacto.com", "12345678"); 
        Contacto contacto2 = new Contacto("Contacto 2", "contacto2@contacto.com", "87654321"); 
        Contacto contacto3 = new Contacto("Contacto 3", "contacto3@contacto.com", "45612378");  

        //Guardamos las tres instancias, guardamos el id del contacto1 para usarlo posteriormente 
        idAEliminar = contactosDAO.guardaContacto(contacto1); 
        contactosDAO.guardaContacto(contacto2); 
        contactosDAO.guardaContacto(contacto3);  

        //Modificamos el contacto 2 y lo actualizamos 
        contacto2.setNombre("Nuevo Contacto 2"); 
        contactosDAO.actualizaContacto(contacto2);  

        //Recuperamos el contacto1 de la base de datos 
        contactoRecuperado = contactosDAO.obtenContacto(idAEliminar); 
        System.out.println("Recuperamos a " + contactoRecuperado.getNombre());  

        //Eliminamos al contactoRecuperado (que es el contacto3) 
        contactosDAO.eliminaContacto(contactoRecuperado);  

        //Obtenemos la lista de contactos que quedan en la base de datos y la mostramos 
        List<Contacto> listaContactos = contactosDAO.obtenListaContactos();  
        System.out.println("Hay " + listaContactos.size() + "contactos en la base de datos");  

        for(Contacto c : listaContactos) 
        { 
            System.out.println("-> " + c.getNombre()); 
        } 
    } 
}




En el momento que ejecutemos la aplicación Hibernate creará la tabla correspondiente en la base de datos (llamada "contactos") y que tiene los siguientes campos:



Como podemos ver la tabla y los nombres de las columnas se generan en base al archivo de mapeo. En donde hemos colocado los nombres de las columnas se han usado estos nombres, en donde no lo hemos hecho se han tomado los mismos nombres que el de los atributos que estamos mapeando.

Si observamos la salida de la consola podemos ver, que en la parte final, se indica esta creación y además las consultas que Hibernate ha generado (revueltas con los mensajes que sacamos a consola). He marcado con rojo los mensajes que mandamos a consola para que sea fácil distinguirlos.



Segun indica la salida en la base de datos solo debemos tener dos entidades, con los nombres "Nuevo Contacto 2" y "Contacto 3". Revisemos la tabla para ver que esto sea correcto:


Como podemos ver, esto es correcto, en la base de datos existen solo los registros indicados, con lo que podemos estar seguros de que nuestra aplicación funciona!!! ^-^.

Entonces, vimos que con Hibernate fue muy simple hacer la manipulación de los datos de una base de datos relacional sin escribir una sola línea de SQL. En aplicaciones de tamaño mediano a grande esto nos ahorrará mucho tiempo (que normalmente usaríamos en escribir el SQL para query, armar algunas de estas de forma dinámica, pasar los parámetros adecuados, recuperar los mismos de un ResultSet, entre otras cosas) para mejorar algunos otros aspectos de la aplicación, como la interfaz gráfica, la lógica del negocio, o realizar más pruebas. Además nuestro código es más simple y por lo tanto fácil de mantener.

Lo único malo es que ahora tenemos que crear mapeos de las entidades con las tablas de la base de datos en un archivo XLM. Es por esto que en el siguiente tutorial veremos cómo realizar este mismo ejemplo pero usando anotaciones en vez del archivo de mapeo ^-^.

Espero que esto les haya sido de utilidad. No olviden dejar sus comentarios, dudas, y sugerencias.

Saludos.

Descarga los archivos de este tutorial desde aquí:

Entradas Relacionadas:

109 comentarios:

  1. ok programador java , como siempre excelente tutorial ya lo estoy implementando . . .

    ResponderEliminar
  2. Gracias:
    quisiera saber que version de Netbeans utiliza, y como queda el ContactosDAO, el main que no me funcionan.
    gracias nuevamente

    ResponderEliminar
  3. Hola Janeth;

    El NetBeans que eso es la última versión liberada, que en este momento es la 6.5. En cuanto al ContactosDAO, queda como en el ejemplo, te pongo el código a continuación.

    ¿Cuál error te da en el main?


    public class ContactosDAO
    {
    private Session sesion;
    private Transaction tx;

    public long guardaContacto(Contacto contacto) throws HibernateException
    {
    long id = 0;

    try
    {
    iniciaOperacion();
    id = (Long) sesion.save(contacto);
    tx.commit();
    } catch (HibernateException he)
    {
    manejaExcepcion(he);
    throw he;
    } finally
    {
    sesion.close();
    }

    return id;
    }

    public void actualizaContacto(Contacto contacto) throws HibernateException
    {
    try
    {
    iniciaOperacion();
    sesion.update(contacto);
    tx.commit();
    } catch (HibernateException he)
    {
    manejaExcepcion(he);
    throw he;
    } finally
    {
    sesion.close();
    }
    }

    public void eliminaContacto(Contacto contacto) throws HibernateException
    {
    try
    {
    iniciaOperacion();
    sesion.delete(contacto);
    tx.commit();
    } catch (HibernateException he)
    {
    manejaExcepcion(he);
    throw he;
    } finally
    {
    sesion.close();
    }
    }

    public Contacto obtenContacto(long idContacto) throws HibernateException
    {
    Contacto contacto = null;
    try
    {
    iniciaOperacion();
    contacto = (Contacto) sesion.get(Contacto.class, idContacto);
    } finally
    {
    sesion.close();
    }

    return contacto;
    }

    public List<Contacto> obtenListaContactos() throws HibernateException
    {
    List<Contacto> listaContactos = null;

    try
    {
    iniciaOperacion();
    listaContactos = sesion.createQuery("from Contacto").list();
    } finally
    {
    sesion.close();
    }

    return listaContactos;
    }

    private void iniciaOperacion() throws HibernateException
    {
    sesion = HibernateUtil.getSessionFactory().openSession();
    tx = sesion.beginTransaction();
    }

    private void manejaExcepcion(HibernateException he) throws HibernateException
    {
    tx.rollback();
    throw new HibernateException("Ocurrió un error en la capa de acceso a datos", he);
    }
    }

    ResponderEliminar
  4. Hola:
    No intente mas con este tutorial, hice el de metadatos y ese si me ejecuto bien.
    Gracias

    ResponderEliminar
  5. Alex, muy bueno el tutorial.
    tenemos dudsa de como hacer un mapeo de 1:n donde la segunda tabla tiene la clave compuesta de la siguiente manera:
    tabla 1: id_tabla1; descripcion (PK: id_tabla1)
    tabla 2: id_tabla1; id_item; descripcion (PK: id_tabla1 e id_item)
    En la clase tabla 2 definimos de la siguiente manera:
    @Entity
    @Table(name="tabla2")
    public class Tabla2 implements Serializable {
    @Id
    @JoinColumn(name="idTabla1", referencedColumnName="idTabla1")
    @ManyToOne(fetch=FetchType.LAZY)
    private Tabla1 idTabla1;
    @Id
    @Column(name = "id_item")
    private Long idItem;
    @Column(name="descr")
    private String descripcion;
    ...
    Utilizando asi la logica considera como el unico Id el de idItem y no el vinculo con tabla1.

    ResponderEliminar
  6. Hola

    En realidad las entidades solo pueden tener un y solo un atributo que sirva como id. Si quieres usar una llave compuesta tienes que usar la anotación @idClass o bien @EmbeddedId. Puedes encontrar información sobre eso aquí:

    http://docs.jboss.org/ejb3/app-server/HibernateAnnotations/reference/en/html_single/index.html

    Por otro lado, me parece que los atributos que usas como asociaciones no pueden ser usados como identificadores, mas bien representantan eso, asociaciones entre entidades.

    Saludos

    ResponderEliminar
  7. Perdón me fato decir que si, tu lógica es correcta el único id debería ser idItem y no la relación.

    Saludos

    ResponderEliminar
  8. LuisRG

    Hola excelente tutorial Alex justo lo que estaba buscando.....
    solo una cosa...Tengo un gran problema porque el programa no me corre devido a que cuando entra a la clase HibernateUtil e intenta generar el sessionFactory siempre me lo retorna como null y en la clase main este es el resultado::
    java.lang.NullPointerException
    at pruebahibernate.ContactosDAO.guardaContacto(ContactosDAO.java:70)
    at pruebahibernate.Main.main(Main.java:30)

    la verdad esq he revisado todo el codigo y aun no encuentro en que estoy fallando....
    pero creo que el problema se debe a que quiza no encuentra o abre el hibernate.cfg.xml...
    si me puedes hechar la mano y gracias por tu tutorial....

    ResponderEliminar
  9. Hola Luis; Podrías decirme en dónde estas colocando el archivo de configuración de Hibernate?.

    También podrías revisar en tu consola a ver si te está dando algún otro error?

    Saludos

    ResponderEliminar
  10. El archivo de configuracion lo estoy colocando siempre en el default package que se crea el solo.....
    y en la consola no me da ningun otro error....

    http://www.4shared.com/file/114905580/25b879c7/Pantallazo-PruebaHibernate_-_NetBeans_IDE_65.html

    Esa es una impresion de pantalla para que observes donde tengo ubicados cada paquete y lo que me imprime en consola....
    te agradesco tu ayuda..... porque me interesa mucho empesar a trabajar con hibernate.

    ResponderEliminar
  11. Pues todo parece estar bien colocado en tu proyecto, lo unico raro que puedo ver es que estas usando una versión vieja del conector de MySQL (estas usando la 3.x, y la última es la 5.x). Puede que esto tenga algo que ver

    Otra pregunta, tu base de datos ya está creada. Si no es así, debes crear una base de datos llamada "pruebahibernate". Si ya esta creada podrías revisar si las tablas se crearón?.

    ResponderEliminar
  12. Haa
    se me olvidaba comentarte que, observe que ,el error puede estar en el archivo de configuracion xml porque cuando depuré el programa, en la clase de HibernateUtil
    en la linea:
    sessionFactory = new Configuration().configure().buildSessionFactory();
    que es la que se pasa al session de contactoDAO me retorna como nula y es por eso que creo que no esta cogiendo el archivo de configuracion para abrir la conexion......
    y ya revice la DB abriendo una conexion desde jdbc y si abre la conexion....
    entonces le he dado vueltas para observar cual sera el problema....

    Muchas Gracias por tu ayuda....

    ResponderEliminar
  13. ok voy a descargar entonces el conector.....Para probar... ee en la DB no se crea la tabla....

    Gracias...
    Si con eso no se soluciona puedo pasarte el proyecto para que le heches un vistaso???

    ResponderEliminar
  14. Si, claro.

    Prueba actualizar el conector y prueba, puede que sea eso.

    Otra pregunta, qué versión de MySQL estas usando?.

    Si con lo del conector no se soluciona mandame tu proyecto a esta dirección:

    programadorjavablog@gmail.com

    para que lo revise con cuidado.

    Saludos

    ResponderEliminar
  15. La version de mysql es esta::

    mysql Ver 14.12 DistribServer version: 5.0.77, for redhat-linux-gnu (i386).

    Te enviare el proyecto porque no me funciono con el nuevo conector.
    tambien no c si es problema pero trabajo sobre linux... pero eso no tiene que ser problema porque las conexiones siempre se hacen igual....
    bueno te mando el proyecto y Muchas gracias por tu atencion......

    Gracias...

    ResponderEliminar
    Respuestas
    1. tengo el mismo error que tú... te lo solucionó?

      Eliminar
  16. TREMENDO! UN DIEZ Es el primer ejemplo que consigo hacer funcionar y a la primera :-)

    ResponderEliminar
  17. Excelente tutorial !!!
    Pero me he encontrado con un problema al implementarlo en oracle, he cambiado el archivo de configuración para poder leer de una base de datos oracle 10g. Pero no consigo arrancarlo me tira el siguiente error al hacer el sessionopen()
    Ocurrió un error en la inicialización de la SessionFactory: org.hibernate.HibernateException: Unable to instantiate default tuplizer [org.hibernate.tuple.entity.PojoEntityTuplizer]


    Si pudieras ayudarme, un saludo

    ResponderEliminar
  18. Buenas noches,
    En primer lugar, enhorabuena por el tutorial ya que es el mejor que he encontrado para empezar con Hibernate.

    Yo me he encontrado con el mismo problema que Jesús. ¿Has conseguido arreglarlo? Yo he leído por ahí que hay que incluir la librería javaassist, pero yo he probado con varias versiones, incluso la versión que aparece en este tutorial y no hay manera...

    ¿Alguien sabe como arreglarlo?

    Gracias

    ResponderEliminar
  19. Hola JAZ;

    Primero que nada gracias por tus comentarios.

    Sobre lo de la libreria me parece que Jesús lo resolvió usando las librerias de Hibernate que vienen ya con el NetBeans, que son más antiguas, en vez de usar las que menciono en el tutorial. Tal vez sea un problema de incopatibilidad o algo así.

    Saludos

    ResponderEliminar
  20. Fenomenal, mejor explicación no pude haber encontrado.
    Saludos!!!

    ResponderEliminar
  21. Gracias, está la teoría justa y un buen ejemplo siempre ayuda .

    Saludos

    ResponderEliminar
  22. Bueno día.
    He echo este mismo ejemplo en NetBeans 6.9.1 y jalo de maravilla, lo pase a Jdeveloper y no me funciono me marca un error en el Dao ContactosDAO, les pongo el error y la linea de la case.
    contacto = (Contacto) sesion.get(Contacto.class, idContacto);


    Esta linea en donde esta el error es en el metodo obtenContacto, al parecer es un campo chico o algo asi, ahora les pongo el error que me da JDeveloper.
    Error(76,62): incompatible types; found: long, required: interface java.io.Serializable

    Gracias.

    ResponderEliminar
  23. Hola Salvador;

    La razón del error me parece que es debido al JRE o JDK, dependiendo si el error te lo da en compilación o en ejecución, que el JDeveloper esté usando, que me parece que en este caso no es el mismo que el que usa el NetBeans.

    Debes asegurarte que usas la versión 5 o superior de Java. Si es el caso, el error podría deberse a algo particular del JDeveloper.

    Saludos

    ResponderEliminar
  24. Hola muy buenas, muy bueno tu tutorial pero no consigo hacerlo andar, siempre obtengo java.lang.ExceptionInInitializerError sin embaro si pruebo el hibernate.cfg.xml para obtener datos si conecta con la BD y me los lista. pero cuadno llamo a HiberateUtil.getSessionFactory() me da la excepcion.

    Alguna sugerencia. Gracias.

    ResponderEliminar
  25. Hola Jose;

    ¿El error no te dá mas detalles? Lo que se me ocurre es que no se puede establecer la conexión a la base de datos. Puede ser que la URL a la misma está mal escrita, o que el usuario o contraseña sean incorrectos. También puede tratarse de permisos, que, si tu base de datos está en otro servidor, no tengas permisos de acceso a dicho servidor. ¿Podrías poner el stacktrace completo de la excepción para revisarlo?

    Saludos

    ResponderEliminar
  26. Gracias por tu respuesta Alex, parece ser que el error radica en que no es capaz de localicar el archivo hibernate.cfg.xml. Lo hize todo de nuevo otra vez y anocheno funcionaba, sin embargo sin tocar a nada hoy abro el proyecto y voala!!! ya funciona. Sin haber tocado una linea de codigo, supongo algunas referencias no se actualizarian o algo asi.

    Aprobecho para hacerte unas consulta,
    1.- ¿porque las clases que acceden a la base de datos implemente serializable?
    2.- Cual es la diferencia entre usar hibernate o hibernate JPA

    ResponderEliminar
  27. Hola Jose;

    Pues que raro jejeje, como tu dices, puede ser que algo no se haya actualizado.

    sobre tus preguntas:

    1.- En realidad las clases que acceden a la base de datos son las clases "DAO" (en este caso "ContactosDAO") las clases que implementan serializables son nuestras "entidades" que representan nuestros registros en la base de datos. En realidad, como menciono en el tutorial, esto no es obligatorio pero es un abuena práctica ya que esto permite a las entidades poder ser serializadas, el cual es un proceso que hace que los objetos puedan viajar a través de un stream desde un origen y ser recreados en el destino. Esto nos permite, por ejemplo, en sistemas distribuidos, crear nuestras entidades en un servidor y enviarlos a otros a través de la red.

    2.- Hibernate es la herramienta que permite manejar las operaciones de base de datos sin tener que escribir una sola línea de SQL.

    Hibernate JPA es lo mismo, solo que usando anotaciones. Las anotaciones básicas (y que enseño en los tutoriales posteriores) son tomadas de la especificación de JPA, la cual es la especificación "oficial" de ORM de SUN (que en realidad tomó prestado mucho de Hibernate).

    Hibernate tiene sus propias anotaciones, las cuales permiten hacer más cosas que las anotaciones JPA (ya que estas pensadas para ser usadas de forma genérica con distintos proveedores de persistencia como eclipselink).

    Espero que esto conteste tus preguntas, en realidad en los siguientes tutoriales, cuando comence el uso de anotaciones, te vas a dar cuenta un poco de lo que te digo que los dos son lo mismo, pero de distinta forma.

    Gracias por tu pregunta, Saludos.

    ResponderEliminar
  28. Gracias por tus respuestas, vi algo por hay sobre las anotaciones, pero personalmente veo mas facil esta otra forma.

    Por ulitmo y si querer ser pesado, no tendras echo algun tutorial similar a este sobre strut, porque me vendria genial.

    Un saludo.

    ResponderEliminar
  29. Excelente! No encontre un tutorial mejor.. Muchisiiimas gracias por el aporte..!
    Paula

    ResponderEliminar
  30. Excelente tutorial.
    Yo tuve el mismo problema
    java.lang.NullPointerException at pruebahibernate.ContactosDAO.guardaContact
    at pruebahibernate.Main.main

    Lo resolvi poniendo las librerias de hibernate que trae netbeans por defecto.

    ResponderEliminar
  31. excelente tutorial ,pero encontre un problema la aplicacion guarda,actualiza,busca todo esta bien solo hay un problema cuando cierro la aplicacion y la vuelvo a ejecutar la aplicacion trato de guardar mas registros se borran los que ya habia ingresado porque como haria pa ke no borre los que ya habian registrado

    ResponderEliminar
  32. si alguien resuelve ese problema comentarlo XD:

    ResponderEliminar
  33. @emerson

    Hola Emerson;

    En realidad esto no es un error. Lo que ocurre es que le estamos indicando a la aplicación que cada vez que se ejecute esta elimine la base de datos anterior, y cree una nueva (que es el comportamiento que indicas). Si quieres cambiar esto solo tienes que modificar la linea que dice:

    <property name="hbm2ddl.auto">create-drop</property>


    Por:

    <property name="hbm2ddl.auto">none</property>

    En el tutorial se indican los otros valores que puede tomar esta propiedad.

    Saludos ^_^

    ResponderEliminar
  34. gracias ya me habia dado cuenta pero gracias por tu respuesta

    ResponderEliminar
  35. @Luis

    Hola Alex, excelente tu tutorial!! lo mejorcito que hay ya por dos años :)

    Lo he hecho todo pero me surge el mismo problema que le sucedía a Luis hace casi dos años, recuerdas cual fue la solución para su problema???

    Muchas gracias por adelantado, saludos!

    ResponderEliminar
  36. @Abraham
    Hola Luis;

    Me parece que e esa ocasión el problema fué que hacia falta colocar un jar en la aplicación, pero la verdad no me acuerdo :S. Mandame tu proyecto para que lo revise con calma a:

    programadorjavablog@gmail.com

    Saludos

    ResponderEliminar
  37. Muy buen tutorial, bien explicado.
    Yo acabo de iniciar con hibernate y me ha quedado todo claro.

    Es cierto hay que tener un poco de conocimientos en cuanto a xml, sintaxis de java, importacion de librerias. etc.

    yo realice todo este ejemplo, pero en lugar de usar net beans utilice ECLIPSE, y todo bien. 0 errores.

    te animo a seguir adelante y gracias por publicar tan grandioso manual.

    ResponderEliminar
    Respuestas
    1. Que tal amigo yo estoy haciendo este ejemplo pero en el eclipse sin embargo me da el error ya puesto arriba

      http://www.4shared.com/file/114905580/25b879c7/Pantallazo-PruebaHibernate_-_NetBeans_IDE_65.html

      Cuales son las librerias que utilizaste? o si te salio dicho error como solucionaste?

      Eliminar
    2. Estas seguro de que eso es eclipse??, talvez te convendria usar maven y sus dependencias para usar hibernet en eclipse

      Eliminar
  38. Hola Alex:

    Excelente el tutorial, uno de los mejores que he visto en español, ojalá hagas de todos los frameworks posibles :)

    Respecto al problema anterior del error en guardar en ContactoDAO, pude notar en mi caso que el error estaba en hibernatenormal.Contacto, precisamente en el método set del id, por lo que eliminé el get y set del id y lo volví a generar; de esa manera desapareció el error y creó la tabla y registros en la base de datos.

    Gracias nuevamente por los grandes tutoriales, gracias al de Spring Framework pude entender cómo funciona dicha herramienta. Así dan más ganas de programar !!

    ResponderEliminar
  39. Hola que tal! muy bueno el tutorial, debo confezar q tambien utilice el de struts2 excelente! ;)

    Solo q e he tenido problemas con esta parte de hibernate, la vdd termine corriendo tu codigo, agregando los mismos jar, cambie el usuario, contraseña, base de datos en el hibernate.cfg con respecto a mi pc.
    Solo q al correrlo me manda esto:

    Exception in thread "main" java.lang.NullPointerException
    at hibernate.mapeos.dao.ContactosDAO.obtenContacto(ContactosDAO.java:97)
    (Osea en los sesion.close(); de los metodos agregar,eliminar, etc, en este caso el de agregar)
    at hibernate.mapeos.Main.main(Main.java:41)
    (En los metodos ya sea agregar, actualizar, lista, etc. dependiendo del que se alla encontrado con respecto al error anterior)
    Java Result: 1

    Que crees q sea?

    ResponderEliminar
  40. @suertudo
    Que tal!! Este tutorial es excelente,,pero tuve el mismo error que todos: Exception in thread "main" java.lang.NullPointerException
    at hibernatenormal.ContactosDAO.guardaContacto(ContactosDAO.java:29)
    at hibernatenormal.Main.main(Main.java:21)
    y no lo he podido descifrar. Use las librerias de hibernate actualizadas, y luego las de Netbeans(esto usando Eclipse) y aun asi no funca..
    Suertudo Como hicistes?
    Un saludo!1

    ResponderEliminar
    Respuestas
    1. Es un poco tarde para responder este mensaje, pues veo que es del 2011. De cualquier forma les comento como lo solucioné:

      En el archivo Contacto.hbm.xml, el autor del tutorial nos dice:

      "El elemento con el que indicamos qué clase es la que estamos mapeando es el elemento "" este elemento tiene los atributos "name" y "table" que nos permiten indicar el nombre completo de la clase y la tabla con la que será mapeada, respectivamente"


      <class name="hibernatenormal.Contacto" table="CONTACTOS">

      En name se define la clase, por lo cual hibernatenormal viene siendo el paquete donde está la clase Contacto.

      En mi caso particular, las clases estaban en un paquete llamado pruebahibernate, por lo que la línea en mi código después de corregirla quedó así:

      <class name="pruebahibernate.Contacto" table="CONTACTOS">

      Con eso quedó solucionado el error, es decir, no estaba bien indicado el paquete donde estaba la clase Contacto.

      Cabe mencionar que para mi prueba estoy usando Netbeans 8.0.2 y hibernate 5.0.1

      Eliminar
  41. @Daniel
    Me respondo a mi mismo(que profundo): Bien.. con el problema que hay en probar este fantastico tuto en Eclipse, parece ser el tema de las librerias. Lo que hice fue: copiar las librerias de hibernate en Netbeans, y un jar que es:commons-logging-1.1, que esta en otra ruta fijensen; a la libreria que creo en eclipse para este proyecto, y a esa misma tambien le agrego la de mysql(osea juntos).
    Les dejo el link para descargarlas:
    http://www.mediafire.com/?z8uba85v10jxx2p
    Igual les conviene fijarse, si tienen netbeans, o sino instalen Netbeans(6.9) y comprueben lo que les digo, de paso exploran otro fantástico IDE.
    Un Saludo!

    ResponderEliminar
    Respuestas
    1. Este comentario ha sido eliminado por el autor.

      Eliminar
    2. Gracias Daniel.
      Usaba Eclipse y no me funcionaba.
      Pero con esos jars corre a la perfeccion.

      Eliminar
    3. Gracias,! despues de mucho intentar, con varias librerias al fin me funciono!! agradezco a @Daniel por los lib's y a Alex por el tuto, muy bueno realmente!
      Saludos

      Eliminar
  42. @Daniel
    Para los que aun no pudieron hacer correr este ejemplo y les sale el que comendo Daniel anteriormente
    -mi solucion fue añadir ambas librerias que aparacente en el netbeans en mi caso 6.7.1 que son
    1.hibernate, 2.hernate jpa y hacer un clean and build y con eso me funciono espero que les ayude

    ResponderEliminar
  43. Hey! muy bueno el tutorial, lo estoy haciendo ahora mismo... (en eclipse)
    Yo venía del tutorial de roseindia.net y al intentar usar la ultima version de hibernate tuve el mismo problema que los acá mencionados: primero no encontraba el archivo de configuración, y cuando cambiaba el path para que lo encuentre, me tiraba un NullPointerException....

    No se si lo mio es una "solución", pero lo que me funcionó es usar el paquete entero que te dan como biblioteca en roseindia.net, con la version de hibernate que incluye. Con tan solo sacarle ese paquete y ponerle la nueva, no me funciona. (supongo que debe ser que tengo que actualizar otra biblioteca de todas las que están incluidas, pero como recién empiezo con hibernate, no tengo idea cuales son).

    Espero le sirva a alguno! ;)

    ResponderEliminar
  44. Tutorial terminado! Excelente ayuda Alex!! muy completa cada explicación! La verdad que te agradezco muchísimo este aporte, y qué loco que te sigan agradeciendo luego de 2 años de haberlo posteado!

    En fin, quería dejar acá mi experiencia con el tema de las bibliotecas necesarias para correr hibernate en general y este tutorial en concreto:

    Como dije en el otro post, también tuve el problema de:

    java.lang.NullPointerException at pruebahibernate.ContactosDAO.guardaContact
    at pruebahibernate.Main.main

    Y sabía que tenia que ver con el tema de las bibliotecas. Ahora bien, había encontrado la forma de hace que ande con las bibliotecas del tutorial de roseindia.net, pero realmente quería hacerlo funcionar con la ultima versión de hibernate, y luego de buscar info (que no encontré mucha que me sea útil), y de probar 200 combinaciones lo logré...

    Para usar la version nueva, importé todo como en este tutorial: (hibernate3, todas las del directorio required menos slf4j-api, bajar por separado el slf4j-api e importar la versión api y simple, tal cual como explica Alex). Ademas de bajar e importar el conector a la base de datos que queramos (yo usé mysql5).
    Y luego, por alguna misteriosa razón, hay que importar también la del directorio jpa:
    hibernate-jpa-version-api-version.Final.jar
    No entiendo muy bien por que, por lo que tenía entendido Java Persistence Api era para hacer, digamos, lo mismo, pero fuera de hibernate... sé que en algún lado hay una conexión pero me parece raro que ni en el tutorial de la pagina oficial de hibernate digan que también es necesario importarlo.
    Por allí me estoy mandando cualquiera, pero al menos está andando en esta primera etapa de aprendizaje!

    Les dejo entonces la lista de jars con los que me funcionó:
    Hibernate viejo, tutorial de roseindia.net:

    antlr-2.7.4.jar
    cglib-full-2.0.2.jar
    commons-collections-2.1.1.jar
    commons-logging-1.0.4.jar
    dom4j-1.5.2.jar
    ehcache-1.1.jar
    hibernate3.jar
    jta.jar
    log4j-1.2.9.jar
    mysql-connector-java-3.1.6-bin.jar

    Si usan esta versión antigua y quieren hacer este tutorial, recuerden sacarle el "5" a la linea:
    org.hibernate.dialect.MySQL5Dialect
    del archivo "hibernate.cfg.xml"



    Ultima version de hibernate, los que me funcionaron a mi:

    hibernate-jpa-2.0-api-1.0.0.Final.jar
    antlr-2.7.6.jar
    commons-collections-3.1.jar
    dom4j-1.6.1.jar
    javassist-3.12.0.GA.jar
    jta-1.1.jar
    hibernate3.jar
    mysql-connector-java-5.1.17-bin.jar
    slf4j-api-1.6.1.jar
    slf4j-simple-1.6.1.jar

    Espero que le sirva a los que recién están empezando y se están volviendo loco con las bibliotecas para que les funcione lo básico de hibernate!

    pd: Con la ultima versión, toda la salida a consola es de color rojo, no se asusten que no son errores! fíjense que luego de esto se generen los system.out del tutorial y verifiquen que se haya generado la tabla y su contenido en la base de datos.

    ResponderEliminar
    Respuestas
    1. Esta solucion me ha sido de mucha ayuda !!!. Agregue hibernate-jpa y funciono.

      Eliminar
  45. Este comentario ha sido eliminado por el autor.

    ResponderEliminar
  46. Hola;

    Muchas gracias a todos por sus comentarios, especialmente a RocketBear por darnos la solución. El "problema" de este tutorial es la versión de las librerias de Hibernate. Con la nueva versión se usan librerias un poco distintas.

    Estaba pensando actualizar el tutorial para la nueva versión pero creo que esperaré a que salga la versión 4 para que aprendamos algunas de las nuevas características con las que contará.

    Saludos y muhcas gracias a todos

    ResponderEliminar
  47. Muy buen tutorial, realmente he aprendido a trabajar con Hibernate, me ha ayudado mucho toda la explicación.

    Ahora bien, pasé horas intentando descifrar el error típico que tantos compañeros han mencionado:

    Exception in thread "main" java.lang.NullPointerException
    at hibernate.mapeos................

    Luego de probar con todas las librerías que existen de Hibernate, pude darme cuenta de que todo el problema está en una simple instancia de la clase HibernateUtil.

    Es decir, en la clase ContactoDAO, dentro del método iniciaOperacion() inicialmente tenemos algo como:

    private void iniciaOperacion() throws HibernateException {
    sesion = HibernateUtil.getSessionFactory().openSession();
    tx = sesion.beginTransaction();
    }


    En realidad, el cambio que yo hice y con el cual todo funcionó perfecto fue simplemente instanciar la clase HibernateUtil, quedando de la siguiente manera:

    private void iniciaOperacion() throws HibernateException {
    HibernateUtil hb = new HibernateUtil();
    sesion = hb.getSessionFactory().openSession();
    tx = sesion.beginTransaction();
    }


    Con sólo ese cambio EL PROBLEMA FUE RESUELTO.

    Es importante mencionar que al final estoy trabajando con

    NetBeans 7.0.1
    Hibernate 3.3.1
    slf4j-1.5.6
    mysql-connector-java-5.1.7.

    Que son las que recomiendas en el tutorial.


    Gracias por tan buen aporte.


    Saludos

    ResponderEliminar
  48. Llevo 1 dia intentando hacer correr este programa y me sigue apareciendo el mismo error:

    Exception in thread "main" java.lang.NullPointerException
    at pruebaHibernate.ContactosDAO.guardaContacto(ContactosDAO.java:35)
    at pruebaHibernate.Main.main(Main.java:29)
    Java Result: 1
    BUILD SUCCESSFUL (total time: 0 seconds

    He reinstalado el netbeans con la version 7.0.1
    tambien tengo los mismos archivos jar en la libreria.

    Tambien e probado con el ultimo comentario de el amigo Julio Briceño, en donde inicializa con HibernateUtil hb=new...

    Pero nada. No se que sea en realidad. Estare muy agradecido en alguien que me aporte una respuesta.

    ResponderEliminar
  49. Muchas gracias por este tutorial, simple y efectivo!!!!!!

    ResponderEliminar
  50. Buen aporte acerca del framework solo una duda me podrias enviar tu nombre completo por la razon de que la bibliografia en un proyecto escolar me piden el nombre completo para de esa manera, no fuera plagio de tu informacion y dar credito de la persona que posteo.

    ResponderEliminar
  51. hola tengo una pregunta cual sera la mejor de estas 3 que expongo yo estoy realizando una aplicacion web con JSF-Hibernate-Spring y tengo 3 preguntas.

    es bueno mantener solo una sesion de hibernate abierta en toda la aplicacion y que todos los usuarios hagan uso de esta????

    es bueno abrir y cerran una sesion por transaccion asi como lo muestra este ejemplo?????

    es bueno crear una sesion abrirla limpiarla cerrarla por transaccion pero obtener la HibernateUtil.getSessionFactory().getCurrentSession() cuando se solicite una transaccion????

    Algo parecido a Open Sesion in View espero que puedas solventar mis dudas Gracias.

    ResponderEliminar
  52. Excelente informacion, me funciono a la perfeccion, incluso cambiando el manejador de base de datos a Derby

    ResponderEliminar
  53. Muy buen tutorial!!!. ahora seria interesante k nos mostraras como hacer un mapeo con mas de 2 tablas tengo algunos errores con eso.

    Gracias por el conocimiento y sigue asi!!!

    ResponderEliminar
  54. Gran tutorial, todas las partes son excelentes.

    Estoy usando la version hibernate 4.1.4 con el mysql connector 5.1.20 desde Eclipse y para solucionar el error de NullPointer... lo unico que tuve que hacer fue crear manualmente la base de datos 'pruebahibernate'.
    Saludos

    ResponderEliminar
  55. Como estan, a mi me sigue saliendo el error este (Exception in thread "main" java.lang.NullPointerException
    at hibernateprueba.ContactosDAO.guardaContacto(ContactosDAO.java:24)
    at hibernateprueba.Main.main(Main.java:19)
    Java Result: 1)
    si alguien me podria ayudar estaria muy agradecido.
    Estoy usando netbeans 7.1 con el hibernate 4.1
    Desde ya gracias

    ResponderEliminar
  56. Muy Bueno este tutorial es lo que estaba buscando y con netbeans que es lo que utilizo normalmente para programar.

    Un saludo y gracias

    ResponderEliminar
  57. Muy buen tutorial mano .. me ayudo bastante ....

    Eres lo maximo

    ResponderEliminar
  58. Hola, antes que todo, excelente el tutorial.

    Una pregunta, ¿cómo pudiera especificar un ID múltiple?

    Supongamos que tengo una tabla llamada "Alumno", por ejemplo, con los campos:

    id, nombre(id), edad

    ¿Cómo pudiera especificar en el archivo "Alumno.hbm.xml" que hay dos id's?

    Espero haberme explicado, saludos.

    ResponderEliminar
  59. Iniciandome en este mundo de Java y encuentro tu blog!!! Super emocionado de encontrar a alguien que explica de una manera tan detalladamente facil para los ojos novatos. Espero echarme todos tus ejemplos y ojalá cuando llegue al ultimo haya nuevos. Has de saber que siempre llegaremos muchos con la emoción de encontrar nuevos tutoriales como los haces. Gracias y a empezar!!!

    ResponderEliminar
  60. Hola Alex, ante todo felicitarte por tu gran trabajo (recuerdame que le diga a tu jefe que te suba el sueldo... :) )
    Solo quería comentarte alguna cosita.
    Creo que tienes un comentario mal, échale un ojo y me dices, donde pones:
    //Eliminamos al contactoRecuperado (que es el contacto3)
    creo que tendría que ser
    //Eliminamos al contactoRecuperado (que es el contacto1)
    y hay algo que no entiendo, veo lógico que en el método manejaExcepcion relances la HibernateException, pero ¿por qué cuando recoges la excepción el el catch (de los métodos para guardar, actualizar y eliminar) ,después de invocar al método manejarExcepcion(he), veulves a ejecutar el "throw he"?¿no es redundante?¿no sería suficiente con un único "throw he" (ya fuese en el catch o en el método manejaExcepcion)?

    Muchísimas gracias por tu tiempo, y por tus tutoriales.

    ResponderEliminar
  61. Excelente tutorial, muchas gracias, y muchas felicidades por este gran aporte! n__n

    ResponderEliminar
  62. Gracias por estos tutoriales, realmente facilita mucho entender el funcionamiento de este framework. Y la manera clara en que lo explica

    Muchas Gracias por el aporte

    ResponderEliminar
  63. Excelente tutorial, el ejemplo me fuciono muy bien.
    Gracias por el aporte

    ResponderEliminar
  64. Excelente tutorial Alex!! Es lo mejor que encontré hasta ahora en la web.
    Muchas gracias por compartir tu conocimiento y por tú predisposición!!

    ResponderEliminar
  65. mmm... yo queria aprender a usar Hibernate sin usar IDE

    ResponderEliminar
    Respuestas
    1. Sin usar IDE, te recomiendo que uses MAVEN, es muy sencillo y te ahorra mucho tiempo, comunícate conmigo te paso el proyecto que tengo, te enseño a correrlo todo desde la consola.

      Eliminar
  66. Excelente !!! Muchas gracias, que razón hay en volver a repasar lo "básico", el session.close fue lo que me ayudó, jajaja, GRACIAS

    ResponderEliminar
  67. Hola a todos,

    en primer lugar agradecer a Alex el gran trabajo con los tutoriales. Son magníficos.

    Respecto al problema que tenéis algunos y que hace que por consola se os muestre el mensaje 'Exception in thread "main" java.lang.NullPointerException', debéis solucionarlo añadiendo todos los jars que incorporan las nuevas versiones de hibernate(la que yo uso es la 4.1.9) en lib/required(son 8 ficheros en concreto).
    Es normal que sólo hayáis añadido los que menciona Alex, pero él hace uso de la versión 3 del framework.

    Por último, os dejo la forma en que debe crearse el objeto SessionFactory en la versión 4 y sucesivas de Hibernate, ya que la forma que comenta el manual ha sido reemplazada en nuevas versiones, tal y como informa la documentación oficial (http://docs.jboss.org/hibernate/core/4.0/javadocs/org/hibernate/cfg/Configuration.html#buildSessionFactory):

    import org.hibernate.SessionFactory;
    import org.hibernate.service.ServiceRegistry;
    import org.hibernate.service.ServiceRegistryBuilder;
    import org.hibernate.cfg.Configuration;
    import org.hibernate.HibernateException;

    public class HibernateUtil {

    private final static SessionFactory sessionFactory;
    private final static ServiceRegistry serviceRegistry;

    static {
    try {
    Configuration cfg = new Configuration().configure("hibernate.cfg.xml");
    serviceRegistry = new ServiceRegistryBuilder().applySettings(cfg.getProperties()).buildServiceRegistry();
    sessionFactory = cfg.buildSessionFactory(serviceRegistry);
    } catch (HibernateException he) {
    System.err.println("Initial SessionFactory creation failed." + he);
    throw new ExceptionInInitializerError(he);
    }
    }

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




    //Un saludo(esto no lo copiéis)







    ResponderEliminar
    Respuestas
    1. Depurando me dice que cuando llega a: HibernateUtil hb = new HibernateUtil(); dentro de ContactoDAO directamente casca y me arroja el famoso error: HibernateUtilorg.hibernate.MappingException: Could not get constructor for org.hibernate.persister.entity.SingleTableEntityPersister

      he puesto lo que tu dices en el Hibernate Util pero nada...

      Eliminar
  68. Hola Alex tengo un pequeño problema con los imports de la clase javaUtil me podrias decir que librerias me faltan, me dice que org no existe

    ResponderEliminar
  69. Ah oye y disculpa tendras algun tutorial asi pero para guardar en base de datos mysql con varias tablas ya relacionadas?? eh encontrado varios pero guardan solo en una unica tabla en la base de datos te agradeceria muchisimo que tuvieras alguno gracias

    ResponderEliminar
  70. Hola Alex!,

    Excelente tutorial, lo he seguido al pié de la letra y me funciona de maravilla, sólo que tuve que hacer algunos pequeños cambios, ya que uso eclipse con maven y eso me facilita mucho el majeno de librerías.

    Saludos Cordiales.

    ResponderEliminar
  71. Hola quisiera saber como puedo llamar estos metodos(insertar,actualizar, eliminar) desde un Formulario. Es decir hacer un formulario con todos los datos del contacto y desde ahí poder insertar, actualizar y modificar.


    Saludos

    ResponderEliminar
  72. Muy buen tutorial! Gracias.. Tienes algun ejemplo de Spring Web Service? Desde la creacion de los xml para luego crear los XSD?

    ResponderEliminar
  73. Fantastico aporte!! Muchisimas gracias capo! Anda de lujo!

    ResponderEliminar
  74. hola gracias por compartir este tutorial, saludos!!!!

    ResponderEliminar
  75. Tengo el Netbeans 8 y pues tenia el mismo problema que no queria ejecutarse bien la aplicacion, pero se solucionó asi como mencionan en comentarios anteriores, inclui la libreria hibernate 4.x y ademas la libreria hibernate 4.x(JPA2.0), pero ademas de esto necesite cambiarle el encabezado a dos paginas para cumplir eso de migracion segun este texto:

    The namespaces for the Hibernate dtd files have changed. From http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd to http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd and from http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd to http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd

    Los 2 archivos que le cambie el encabezado es: hibernate.cfg.xml y contacto.hbm.xml. Espero que esto les ayude, saludos.

    ResponderEliminar
    Respuestas
    1. tambien estoy usando Netbeans 8 pero me sale error

      Eliminar
    2. Este comentario ha sido eliminado por el autor.

      Eliminar
    3. Pues a mi me sigue sin funcionar... netbeans 8 con ubuntu, he cambiado los namespaces, añadido las librerias directamente desde netbeans, las 4.X, JPA el conector y hasta el ModelGen (que creo que no sirve para esto xD), funciono bajo el JDK 1.7 ... he cambiado tambien la sesionfactory como se dice en los comentarios....
      Creo que el error puede ser porque las librerias las importo directamente desde netbeans, sin bajarme librerias de ninguna web ni nada... pero no se... en mi codigo en lugar de Contacto es Jugador... pero por lo demás es igual...
      he probado por si las moscas a cambiar el class name de Contacto.hbm.xml ya que yo estoy acostumbrado a utilizar el MVC con lo que mi estructura sería: pero tampoco... en fin. copio y pego mi archivo de configuración por si alguien ve algo raro:

      ?xml version="1.0"?>
      !DOCTYPE hibernate-mapping PUBLIC
      "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
      "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
      hibernate-mapping>
      class name="Proyecto_Apuestas.proyecto_apuestas.Modelo.Jugador" table="JUGADORES">
      id name="ID" column="ID">
      generator class="identity" />
      /id>
      property name="nombre" type="string" column="NOMBRE" />
      property name="numero" type="int" column="NUMERO"/>
      property name="goles" type="int" column="GOLES"/>
      property name="tarjetas" type="int" column="TARJETAS"/>
      /class>
      /hibernate-mapping>

      Eliminar
  76. Ahora que estoy incursionandome en hibernate es genial realmente, me encanto tu tutorial.
    Lo unico tengo una duda que capaz que me la puedas solventar. Realizando ejemplos en netbeans cuando hago el mapeo de la base de datos a clases, me genera el .java y el .xml.
    Mi duda es, en que momento se utilizan las denominadas "hibernate annotations"?
    Desde ya gracias. Saludos.

    ResponderEliminar
    Respuestas
    1. se supone que hay dos formas de utilizar hibernate, por fichero de configuracion y por anotaciones.. la verdad que mi proyecto empecé a utilizarlo por anotaciones y por lo menos me creaba las tablas... ahora he intentado probar por fichero de configuracion y ni crea las tablas xD, se supone que da igual como lo hagas, aunque por fichero es menos lioso.

      Eliminar
  77. Buenas, excelente tutorial, me estoy iniciando en JAVA y tengo un error, tal vez basico, al actualizar un registro, luego vuelvo a la grilla principal y trato de actualizar otro registro y ya no me funciona, que podria ser?
    Gracias,
    Hibernate-Netbeans-Mysql

    ResponderEliminar
  78. Excelente tuto, gente como vos hace falta, saludos!

    ResponderEliminar
  79. Perfecto...
    Lo que necesito para engrandecer el propio conocimiento de una manera autónoma.................

    ResponderEliminar
  80. Este comentario ha sido eliminado por el autor.

    ResponderEliminar
  81. Este comentario ha sido eliminado por el autor.

    ResponderEliminar
    Respuestas
    1. Este comentario ha sido eliminado por el autor.

      Eliminar
  82. Por si alguien le ocurre... despues de 7 horas he arreglado el error, además de utilizar todos los aportes de los comentarios a saber(el hibernate util modificado, el sessionfactory modificado y demás) no se os olvide incluir sendos setters y getters para el ID además (y así es como he solucionado mi error) añadir un constructor para contacto con todos los campos utilizados excepto el del id.

    ResponderEliminar
    Respuestas
    1. Hola ruben como lo solucionaste ? tuve el mismo error

      Eliminar
  83. Buenas, desde ya gracias por el aporte, justo lo que buscaba. Tengo una duda que me esta matando, yo quiero hacer una aplicacion que se encargue con la ayuda de hibernet de generar el esquema de base de datos, y luego de que lo genere este listo para su uso. Mi duda es la siguiente, vos explicas que en el xml para genrar el esquema debemos utilizar create-drop y como una de las opciones elegiste create-drop, pero por lo que entendi yo, eso hace que cada vez que vos vallas a ejecutar el codigo borres el esquema existente(osea las tablas con toda sus registros que pudieras tener guardados) para luego volver a crear el esquema nuevamente. Bueno de ser asi como logro crear una sola vez el esquema para luego usarlo???

    ResponderEliminar
  84. Este comentario ha sido eliminado por el autor.

    ResponderEliminar
    Respuestas
    1. Este comentario ha sido eliminado por el autor.

      Eliminar
  85. Este comentario ha sido eliminado por el autor.

    ResponderEliminar
  86. Este comentario ha sido eliminado por el autor.

    ResponderEliminar
  87. Hola buenas tardes. Excelente tutorial, yo me encuentro haciendo algo muy similar pero en una actividad para guardar peliculas.
    El caso es que me da el siguiente error al compilar el main.java:

    Ocurrió un error en la inicialización de la SessionFactory:org.hibernate.service.spi.ServiceException: Unable to create requested service [org.hibernate.engine.jdbc.env.spi.JdbcEnvironment]

    Tengo el ContactoDAO, que yo llamo PeliculaDAO.java y el HibernateUtil.Java que no se muy bien desde donde lo llamo.

    Gracias.

    ResponderEliminar