Ejemplo sencillo con Hibernate-annotations

De ChuWiki

Introducción[editar]

Con hibernate-core (la base de hibernate), podemos hacer que nuestras clases se almacenen en una base de datos haciendo ficheros de mapeo XML, en los que se indica cómo se guarda en base de datos cada clase. Con hibernate-annotations podemos hacer esto mismo, pero reemplazando los ficheros XML pon annotations java en la misma clase.

Vamos a hacer aquí un pequeño ejemplo usando Hibernate-annotations. Haremos una sencillo java bean al que pondremos las annotations pertinentes para poder almacenarlo, modificarlo y consultarlo en base de datos. Luego, un programa de ejemplo instanciará ese java bean, lo insertará en base de datos, lo consultará, modificará alguno de sus atributos y volverá a guardarlo.

Aquí tienes todos los fuentes completos de este ejemplo.

¿Qué necesitamos?[editar]

Para este ejemplo necesitamos lo siguiente:

  • Una base de datos Categoría:MySQL, con una base de datos de nombre hibernate, con un usuario hibernate de password hibernate y con permisos suficientes.
  • mysql-connector-java-5.0.4.jar El conector de java con la base de datos. Por supuesto, la versión adecuada para nuestra base de datos.
  • Bajarnos hibernate-annotations, desempaquetarlo y usaremos los jar siguientes (se indica delante el subdirectorio en el que se encuentran):
    • hibernate-annotations.jar
    • lib/ejb3-persistence.jar
    • lib/slf4j-api.jar
    • lib/hibernate-commons-annotations.jar
    • lib/dom4j.jar
    • lib/hibernate-core.jar
    • lib/test/jta.jar
    • lib/test/javassist.jar
    • lib/test/log4j.jar
    • lib/test/slf4j-log4j12.jar
    • lib/test/commons-collections.jar

Los que vienen debajo de lib/test vienen con el zip más que nada por el ejemplo. Si no los queremos coger de ahí, deberemos descargarlos, eso sí, versiones compatibles.

Una opción para conseguir todos estos jar automáticamente es hacer un proyecto maven con hibernate-annotations


Nuestro java bean[editar]

Vamos a hacer el java bean que será persistente en base de datos usando las anotaciones. Lo primero, es declarar la clase, poniendo @Entity delante de la declaración de la clase. Opcionalmente podemos poner también @Table(name = "VUELO"), donde "VUELO" es el nombre que queremos para la tabla de base de datos que guarde nuestro java bean. Si no ponemos nombre, se usará como nombre el nombre de la clase (Flight en nuestro ejemplo)

...
/**
 * Clase persistente en base de datos con annotations.
 * 
 * @author Chuidiang
 */
@Entity
@Table(name = "VUELO")
public class Flight {
   ...

Aunque por sistema se suele poner que estas clases persistentes implementen la interface Serialzable, esto no es obligatorio salvo que pretendamos pasar estas clase a través de rmi o similar.

Ahora ponemos un atributo id, que hará de clave de nuestro dato. En el método getId() ponemos las annotations @Key y @GeneratedValue. Con esto indicamos que es la clave primaria y que debe ser generada automáticamente por la base de datos. Si no ponemos @GeneratedValue, debemos nostros en código encargarnos de dar claves nuevas a las entidades.

...
   private Long id;

   /** Persistente como clave y valor generado por la base de datos */
   @Id
   @GeneratedValue
   public Long getId() {
       return id;
   }

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

Ponemos otro atributo normalito más, el nombre del vuelo. Al ser un atributo de un tipo básico, pondremos la annotation @Basic. Podemos, opcionalmente, poner también @Column(name = "NOMBRE"), donde "NOMBRE" es el nombre que deseamos para la columna en la base de datos. Si no lo ponemos, se usará por defecto el nombre del atributo, firstname en el ejemplo.

...
    private String firstname;

    /** Persistente, un tipo basico (string) */
    @Basic
    @Column(name = "NOMBRE")
    public String getFirstname() {
        return firstname;
    }

    public void setFirstname(String firstname) {
        this.firstname = firstname;
    }

Las fechas son más complejas, ya que no hay forma de saber a priori si un Date de java es un TIME, DATE o TIMESTAMP de base de datos (sólo hora, sólo fecha o fecha y hora). Por ello, debemos poner la annotation @Temporal, indicando detrás qué tipo de campo deseamos en base de datos. Por supuesto, podríamos indicar también el nombre de la columna.

...
import java.util.Date;
...
    private Date fecha;

    /** Una fecha. Debemos indicar si es DATE, TIME o TIMESTAMP */
    @Temporal(TemporalType.TIMESTAMP)
    public Date getFecha() {
        return fecha;
    }

    public void setFecha(Date fecha) {
        this.fecha = fecha;
    }

Aquí puedes ver la clase Flight.java completa.


Fichero de configuración Hibernate[editar]

Necesitamos un fichero de configuración XML para hibernate. Este fichero básicamente contiene los nombres de las clases que son persistentes y los datos de conexión a base de datos. Las clases persistentes se indican con la etiqueta XML <mapping class="..."/>. El resto del fichero XML es similar al del Ejemplo sencillo con Hibernate. Aquí tienes el contenido del fichero

<!DOCTYPE hibernate-configuration PUBLIC
    "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
        "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
	<session-factory>
		<!-- Database connection settings -->
		<property name="connection.driver_class">com.mysql.jdbc.Driver</property>
		<property name="connection.url">jdbc:mysql://localhost/hibernate</property>
		<property name="connection.username">hibernate</property>
		<property name="connection.password">hibernate</property>
		<!-- JDBC connection pool (use the built-in) -->
		<property name="connection.pool_size">1</property>
		<!-- SQL dialect -->
		<property name="dialect">org.hibernate.dialect.MySQL5Dialect</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 class="com.chuidiang.ejemplos.hibernate_annotations.Flight" />
	</session-factory>
</hibernate-configuration>


Clase útil para obtener la sesión de Hibernate[editar]

Al igual que hicimos en el Ejemplo sencillo con Hibernate, necesitaremos una clase HibernateUtil.java que nos facilite obtener una sesión de Hibernate. En esta clase es donde indicamos dónde está nuestro fichero de configuración de hibernate: el fichero hibernate.cfg.xml. La clase es la siguiente

package com.chuidiang.ejemplos.hibernate_annotations;

import java.io.File;

import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.AnnotationConfiguration;

/**
 * Clase de utilidad para obtener la sesion de hibernate.
 * 
 * @author Chuidiang
 * 
 */
public class HibernateUtil {

    private static final SessionFactory sessionFactory;

    static {
        try {
// Si no ponemos fichero, intenta cargar "/hibernate.cfg.xml" en el raiz
            sessionFactory = new AnnotationConfiguration().configure(
                    new File("hibernate.cfg.xml")).buildSessionFactory();
        } catch (Throwable ex) {
            // Log exception!
            throw new ExceptionInInitializerError(ex);
        }
    }

    public static Session getSession() throws HibernateException {
        return sessionFactory.openSession();
    }
}


El código de ejemplo[editar]

Ahora sólo nos queda hacer el código del ejemplo, similar en todo al del Ejemplo sencillo con Hibernate. En el constructor de la clase hacemos las siguientes llamadas a métodos que hemos preparado

...
    public Ejemplo1() {
        // Se inserta
        Long id = insertFlight();

        // Se consulta y muestra por pantalla
        listFlights();

        // Se modifica
        updateFlight(id);

        // Se vuelve a consultar y mostrar por pantalla
        listFlights();
    }
...

El método de inserción simplemente obtiene la sesión con Hibernate, instancia una clase Flight, rellena sus datos (excepto el id) y la salva en base de datos

    private Long insertFlight() {
        // Se obtiene la sesion
        Session s = HibernateUtil.getSession();
        s.beginTransaction();

        // Se instancia la clase Flight y se rellenan sus datos
        Flight f = new Flight();
        f.setFirstname("Nombre vuelo");
        f.setFecha(new Date());
        
        // Se salva en base de datos
        s.save(f);
        s.getTransaction().commit();

        return f.getId();
    }

Aquí puedes ver el código completo de la clase Ejemplo1.java.