Hibernate

« Entradas repetidas en los feeds y Ultimate Tag Warrior | Abridores de paquetes de plástico »

Usar JDBC es complejo y muy dependiente de la estructura de los datos. Sería más natural y mucho más sencillo trabajar directamente con objetos, pero es imposible con las BBDD relacionales, y las BBDD orientadas a objeto están todavía muy verdes.

La mejor opción entonces es utilizar un motor de persistencia, que es el componente software encargado de traducir entre objetos y registros. Un motor de persistencia de código abierto es Hibernate, que nos permitirá hacer cosas como poder guardar un objeto en la base de datos simplemente con session.save(miObjeto) o borrarlo con session.delete(miObjeto).

Usa el mecanismo de reflexión de Java, que permite a un objeto en ejecución examinarse y manipularse a sí mismo, en contra de, por ejemplo, JDO, que necesita que modifiquemos los archivos de las clases.

Vamos a tener un archivo properties (hibernate.properties) o un archivo xml (hibernate.cfg.xml) para la configuración, una serie de JavaBeans que son las clases a persistir y en las que cada campo se asociará con una columna de la BBDD, y un archivo xml por cada una de estas clases (NombreClase.hbm.xml) que indica el mapping entre objetos y relaciones.

Este sería el aspecto del JavaBean que representa una sucursal en una supuesta aplicación:

package net.mundogeek.ejemplo;

public class Sucursal {
  private String director, telefono;
  private long idSucursal;

  public Sucursal(){
  }

  public Sucursal(String director, String telefono, long idSucursal) {
    this.director = director;
    this.telefono = telefono;
    this.idSucursal = idSucursal;
  }

  public long getIdSucursal(){
    return idSucursal;
  }

  public void setIdSucursal(long idSucursal) {
    this.idSucursal = idSucursal;
  }

  // ...
  // getters y setters para telefono y director
}

Y este el del fichero de mapping de hibernate correspondiente:

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

<hibernate-mapping>
  <class name="net.mundogeek.ejemplo.Sucursal" table="Sucursal">
    <id name="idSucursal" type="java.lang.Long">
      <column name="id_sucursal" />
      <generator class="native" />
    </id>
    <property name="director" type="java.lang.String">
      <column name="director" length="25" />
    </property>
    <property name="telefono" type="java.lang.String">
      <column name="telefono" length="25" not-null="true" />
    </property>
  </class>
</hibernate-mapping>

Como vemos la etiqueta class se utiliza para asociar nuestra clase a una tabla concreta de la base de datos. Las etiquetas que se sitúan por debajo de class nos permiten definir la relación entre las propiedades de la clase y las columnas de la base de datos. La etiqueta id se usa para identificar el campo que actuará como clave primaria e indicar el tipo que va a tener (Long en este caso), así como la columna de la base de datos en la que se almacenará el campo y la forma de generar la clave (en este caso, native, que depende de la base de datos que usemos; podríamos haberle indicado por ejemplo que simplemente fuera sumando 1 cada vez con increment, o incluso crear nuestra propia clase generadora). A continuación tenemos una serie de etiquetas property, una por cada propiedad, que funcionan de forma parecida a id, indicando el nombre de la propiedad de la clase (atributo name) su tipo (atributo type) y la columna a la que se mapea (atributo name de column).

Como sabemos, las tablas también pueden tener relaciones entre ellas. En Hibernate podemos declarar relaciones N:M mediante la etiqueta many-to-many, 1:N con one-to-many y N:1 con many-to-one.

Por ejemplo podríamos tener una tabla de trabajadores y querer indicar para qué sucursal o sucursales trabaja cada uno de ellos (N:M, many-to-many). Tendríamos entonces una tabla sucursal, una tabla persona, y una tabla persona_sucursal para relacionarlas.

Veamos cómo podemos tener una colección de trabajadores en la clase Sucursal y que Hibernate sea capaz de rellenarla viendo la estructura de la base de datos y nuestro archivo de mapping.

<set name="personas" table="persona_sucursal" cascade="save-update">
  <key column="id_sucursal"/>
  <many-to-many class="net.mundogeek.ejemplo.Persona" column="id_persona"/>
</set>

Los conjuntos se representan en el archivo mapping de hibernate mediante la etiqueta set (también tenemos otras colecciones como list, map, bag o array). Esta etiqueta va a tener un atributo name, con el nombre de la propiedad de la base de datos asociada; un atributo table, con la tabla mediante la que implementamos la relación (persona_sucursal) y un atributo cascade que nos indica qué hacer con las tuplas de la tabla persona relacionadas con una sucursal cuando se modifique o borre esta sucursal (save-update indica inserción y modificación en cascada, delete, borrado en cascada; all, todas las operaciones en cascada y none ninguna).

La etiqueta set va a contener una etiqueta key, en la que indicamos la clave ajena del objeto actual en la tabla que implementa la relación que es la que se utiliza para diferenciar las instancias de la colección y una etiqueta many-to-many que indicará la clase de los objetos que vamos a tener en la colección y cuál es la clave ajena a su tabla en la tabla persona_sucursal.

Si quisiéramos que la asociación fuera bidireccional (una colección de las sucursales en que trabaja en la clase Persona) tendríamos que añadir otra etiqueta set en el mapping de Persona, pero añadiendo en este caso un atributo inverse="true".

Las relaciones one-to-many y many-to-one funcionarían de forma parecida, solo que no necesitamos una tabla nueva, sino que tendremos una clave foránea de una de las tablas a la otra (si una persona sólo puede trabajar para una sucursal, Persona sólo necesita una propiedad de tipo Sucursal con la sucursal en la que trabaja y no una colección; el otro extremo, Sucursal, si necesitará una colección con las personas que trabajan en la sucursal). En Sucursal.hbm.xml tendríamos:

<set name="personas" table="persona">
  <key column="id_sucursal"/>
  <one-to-many class="net.mundogeek.ejemplo.Persona"/>
</set>

Y en Persona.hbm.xml:

<many-to-one name="sucursal" column="id_sucursal"/>

Ahora que ya hemos visto como indicarle a Hibernate la correspondencia entre nuestras clases y las tablas de la BBDD, vamos a ver cómo utilizaríamos esta API.

Lo primero que tendríamos que hacer para empezar a utilizar Hibernate sería crear un nuevo objeto Configuration para poder indicarle dónde se encuentra el archivo de configuración:

Configuration cfg = new Configuration();
cfg.configure(RUTA_ARCHIVO_CONF);

A partir del hibernate.cfg.xml podemos crea un SessionFactory, que es el objeto mediante el cual abrimos nuevas sesiones de Hibernate.

SessionFactory sessionFactory = cfg.buildSessionFactory();
Session session = sessionFactory.openSession();

Para insertar objetos en la BBDD usaremos el método save(Object objeto) de Session, para insertar o actualizar si ya existe saveOrUpdate(Object objeto), para borrar delete(Object objeto) y para cargar un objeto desde la BBDD get(String clase, Tipo id) o load(String clase, Tipo id) que devuelven el objeto de la clase indicada por el primer parámetro y con identificador el segundo parámetro si es que existe en la BBDD.

Para hacer búsquedas en la base de datos podemos usar find(String consulta) que devuelve una lista con los resultados, o iterate(String consulta) que devuelve un iterador, o bien crear un objeto Query usando createQuery(String consulta) y llamar más tarde al método find() del Query. La consulta en todos los casos estará escrita en un lenguaje similar a SQL propio de Hibernate llamado HQL (Hibernate Query Language). Otra opción sería trabajar con objetos Criteria.

Relacionadas

Comentarios
  1. eynob

    Muy buen resumen, lo vamos a usar

  2. Si le resulta útil al menos a una persona ya me doy por satisfecho :)

  3. Yo lo tengo que usar dentro de un par de meses para un proyecto, así que me lo "apunto" en los marcadores ;-)

    Gracias!!

  4. Muy bueno.
    Supongo que no será útil para todos los geek pero en mi caso sí que me interesa.

  5. Una excelente introducción. Yo solo he trabajado con iBatis, y tu explicación ha servido para hacerme una idea muy clara de como funciona Hibernate. Añadido a del.icio.us ;)

    Saludos

  6. Muy buena intro, haber si de estas empiezo a utilizarlo en mis desarrollos.

    saludos

  7. Gerita

    Excelente!!! me ayudo mucho a aclarar muchas dudas…

  8. Sencillo y presciso. Buena explicacion. Felicitaciones Amigo. Espero tus siguientes aplicaciones.

    Saludos

  9. Dave

    Alguien tiene el hello world en Hibernate??No me aclaro con los mapeos y me gustaria verlo reflejado en un ejemplo. A ver si alguien me puede ayudar. He mirado por inet, y los k hay les falta algo o estan mal explicados. Os lo agradecere

    Gracias

  10. Jhon Cuervo

    como diablos hago para hacer una consulta y me la guarde en una lista para mostarala al usuario

  11. Alda

    Estoy tratando de usar Hibernate con MySQL, pero en realidad no tengo un BD "como Dios manda" sino un conjunto de tablas inconexas, no aplica many-to-one, ni nada de eso, no hay Primary Keys… es un desastre, pero no puedo modificarla… Then, debo trabajar con ella tal cual… El punto es que no paso del buildSessionFactory… Por alguna razón que no entiendo no puede crear la bendita Session…
    Puedes darme alguna luz???

  12. Jesse James

    si buen resumen en mi trabajo usamos Hibernate como framework para la base de datos aveces dentro del hibernate tmb usamos el metodo hibernateTemplat().saveall o sino deleteall o sino creamos metodos donde creamos obejtos del tipo Criteria para jalar de la base de datos y y si queremos del agregamos Restriccion q seria en SQL un WHERE pasandole como parametro en ("nombre_campo_columna",variable) y metemos esa consulta en un List propio del objeto criteia es decir si creamos Criteria criteria = session.createCriteria(Mi_Clase.class);
    hay toy extrayendo todo y luego aca
    Criteria criteria = session.createCriteria(Mi_Clase.class)
    criteria.list();
    hay toy metiendo todo lo extraido de la base de datos de esa clase ya mapeada a una lista q en un metodo se pudiera retornar para su uso
    por ejemplo

    ListaPruebaCriteria = getMiclaseCriteria();

    el metodo getMiclaseCriteria() me estaria traendo toda la data de tabla con la cual la clase llamda Mi_Clase a sido mapeada cave resaltar q al meter a la lista la data jalada de la tabla se a metido a la lista una serie de objetos del tipo Mi_Clase con sus campos debidamente seteados con la data de la base de datos cada campo de la base de datos con registro se a seteado a cada cada variable de la clase Mi_Clase esa relacion se debe al mapeio hecho de esa clase como ya se explico mas arriba en esta web ahora para extraer cada objeto de la lista y a la ves extraer cada dato seteado a ese obejto se puede hacer lo siguiente un for de la siguiente forma:

    for(Iterator iterMi_Clase = ListaPruebaCriteria.iterator(); iterMi_Clase.hasNext(); ){
    //se procede al Casteo de la Lista al Objeto
    //Mi_Clase

    Mi_Clase mi_clase =
    (Mi_Clase)iterMi_Clase.next();

    /*con eso recorremos cada campo de la lista q obtuvmos del criteria traido de la BD y el casteo nos va permitir usar los metodos Get y Set del objeto Mi_Clase de la siguiente manera*/

    String nombre = mi_clase.getNombre();

    }

    buenos amigos espero q les aya servido de algo este pequeño resumen de como poder usar el criteria del Hibernate

  13. alex

    srs, estoy recien ahciendo una investigacion sobre hibernate,spring,struts, ejbv3.0,jsf. para una propuesta de desarrollo ..
    mi pregunta.
    cuales son las deficiencias de Hibernate con respecto a trabajar con EJBv3.0 y JDBC?
    he trabajado bastante tiempo con j2ee, pero como recien estoy investigando me gustaria que me ayudases en poder tener una respuesta tecnica a lo que pregunto.

    atte.
    Claudio Nuñez

  14. Sorrow

    Bastante resumido me recordaste que tenia que hacer el mapping en el hibernate :P

  15. yasleidy

    hola, he leido mucho sobre hibernate y me gustaria trabajarlo pero cuando le he tratado de descargar desde su sitio oficial el archivo baja corrupto, si algui me podria orientar en donde lo puedo descargar, gracias….

  16. aurora

    me gusta mucho lo voy a usar para mi tesis

  17. EDS_jorge

    Alguien puede darme alguna ventaja real del uso de hibernate sobre jdbc?, no sólo el hecho de poder persistir objetos directamente.

    Gracias!!

  18. sword

    Hibernate es muy bueno con el mundo objeto-relacional, para trabajar con objetos puros, la librería efectiva y eficiente para Java y .Net es el db4o… eso si trabajan con objetyos 100% puros…

  19. Char

    Buena info.

  20. Cesar

    quiero recuperar una lista de cuentas pero al momento que la ejeciuto me sale este error

    en el Dao trabajo con esta consulta, la relacion de many to many

    Query consulta = sesion.createQuery("from Cuenta cuenta where rol =? and cuenta.usuario.apellidos like ? " );

    List listaC = (List) su.recuperar(r1,"Ve");
    for (Cuenta cuenta:listaC)
    System.out.println(listaC);

    el error es este:

    Exception in thread "main" java.lang.ClassCastException: [Ljava.lang.Object; cannot be cast to edu.unl.comun.negocio.modelo.Cuenta

    me pueden ayudar donde esta la falla en la consulta o cuando deseo recuperar

  21. Jhan Carlos Herrera Perez

    tiene que ver con problemas de Casting mas bien es eso en que parte a saber!!!

  22. Rodolfo

    el hibernate te da la """gran ventaja""" de no tener que utilizar JDBC o bien, simplemente no te haces dependiente de tomcat, solo requieres programar en objetos planos un poco de xml y HSQL que es el lenguaje de consultas para Hibernate, para todo esto requieres de conceptos como VO y BO que significan Value Object y Bussiness Object respectivamente. Todo esto es muy interesante

  23. mon

    muy buena esta intro! me acabo de poner con Hibernate y no había oído en mi vida ese nombre. Esto me ha servido para saber cómo va y por dónde hay que agarrarlo.

    muchas gracias

  24. Lucas

    Esta bueno pero ¿como configuras la propiedad en el .cs? ya que cuando lo quiero probar me tira error.
    Gracias

  25. muy interesante este articulo gracias por compartirlo

  26. Miguel

    Quisiera que un manual de hibernate en español

  27. fantasmax

    Agradezco que haya tipos como usted, que entienden la belleza de compartir su conocimiento. Esta de puta m… este artículo, me ha ayudado un chingo.

    Espero tener la suerte de encontrarme con otro artículo de tan buena calidad en otro momento.

Deja un comentario