Hibernate

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.

Comentarios
  1. eynob

    Muy buen resumen, lo vamos a usar

    Responder

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

    Responder

  3. Yo lo tengo que usar dentro de un par de meses para un proyecto, así que me lo “apunto” en los marcadores 😉

    Gracias!!

    Responder

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

    Responder

  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

    Responder

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

    saludos

    Responder

  7. Gerita

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

    Responder

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

    Saludos

    Responder

  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

    Responder

  10. Jhon Cuervo

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

    Responder

  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???

    Responder

    • Orantz

      Hola, Alda. No se si te sirve de algo ahora mi respuesta ya que ha pasado un tiempo :D. Pero x si alguien busca por internet algo parecido a tu problema te pongo lo q creo q seria la solución.

      Por un lado mata al que hizo la base de datos :P.

      Luego si tienes tablas inconexas (nunca lo habia visto :O ) Tabien tendras que tener objetos inconexos. De esta manera si tu tienes tu sucursal que tiene su personal (supongo que tendra la id o algo asi del personal) pero no esta unido a la tabla personal por ningun foreing keig (o algo asi) entonces yo me crearia un objeto sucursal con los mismos datos que mi tabla y un objeto personal con sus datos igual que en la tabla.

      Luego al guardar con hibernate trabajaria igual q en sql por un lado rellenaria los datos de sucursal (1, “Paco”, “987909090”, 2) y por otro los de personal (2, “Pepito de los palotes”, …) pero tendras que ser tu la que compruebe que no haya errores de claves externas incorrectas y cosas asi asi que tendrias que hacer primero un find (o un sql con lo que quieras) para ver si existe el trabajador 2 y luego hacer ambos sabes.

      Esto es lo que creo, no se si me explicado bien

      Responder

    • Orantz

      Algo como
      public class Sucursal {
      private String director, telefono;
      private long idSucursal,personal ;
      //… Setters y Geteers
      }

      public class Personal{
      private String nombre;
      private long id;
      //… Setters y Geteers

      Sin ligar ambos como si fueran objetos que no tienen nada que ver.

      Luego,
      Datastore ds = Hibernate.createDatastore();
      ds.storeClass(Sursal.class);
      SessionFactory sessionFactory =ds.buildSessionFactory();
      Session session = sessionFactory.openSession();

      // Crear sucursal nuevo en bd
      Sucursal newSuc = new Sucursal();
      newSuc.setIdSucursal(1);
      newSuc.setDirector(“Paco”);
      newSuc.setTelefono(“000000000”);
      newSuc.setPersonal(2);

      //Crear personal bd
      Persona newPer = new Personal();
      newPer.SetId(2);
      newPer.setNombre(“Pepito”);

      //Guardar ambos
      session.save(newPer);
      session.save(newSuc);

      Antes de hacer los saves es cuando tendrias que comprobar la integridad de la bd en este caso no hace falta pq introduzco las dos tablas y puedes ver que hay un personal con id 2 en la tabla personal. Pero si tuvieras que insertar personal que ya existiera en la bd tendrias que comprobar manualmente si existen.

      Además las sql que hagas para solo sucursal o solo personal te valdra el metodo find o load pero si quieres sacar el nombre del personal por sucursal tendras que hacer una sql manualmente o sacar por un lado los datos de la sucrusal y por otro el de sus empleados y luego mostrarlos tu.

      HASTA LEG

      Responder

  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

    Responder

  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

    Responder

  14. Sorrow

    Bastante resumido me recordaste que tenia que hacer el mapping en el hibernate 😛

    Responder

  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….

    Responder

  16. aurora

    me gusta mucho lo voy a usar para mi tesis

    Responder

  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!!

    Responder

  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…

    Responder

  19. Char

    Buena info.

    Responder

  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

    Responder

  21. Jhan Carlos Herrera Perez

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

    Responder

  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

    Responder

  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

    Responder

  24. Lucas

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

    Responder

  25. muy interesante este articulo gracias por compartirlo

    Responder

  26. Miguel

    Quisiera que un manual de hibernate en español

    Responder

  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.

    Responder

  28. MGEO

    Alguien me puede ayudar con una aplicación pequeña funcionando con struts e hibernate….

    Responder

  29. kvieres

    Por fin algo de hibernate explicado como la gente, gracias, se va a mis bookmarks

    Responder

  30. David

    Buenas.
    Gracias por el tutorial.
    En respuesta a las ventajas de Hibernate…
    Hibernate es la implementación de una capa de persistencia. Esto tiene como ventajas:
    1. La independencia del sistema gestor de base de datos a utilizar. Como se describe en el tutorial. El lenguaje para realizar Querys es HSL (propio de Hibernate). Esto permite que no haya que cambiar nada de código para cambiar de Sistema Gestor de Base de Datos. Solo cambiar un parámetro en el fichero de configuración de Hibernate.
    2. Hibernate implementa una especie de caché, guardando datos en su sesión. Esto permite liberar la carga a la base de datos y permitir así multitud de consultas simultaneas sin colapsar la base de datos.

    Un saludo.

    Responder

  31. Gustav

    El problema de mucha gente, es que sabe mucho de una determinada cosa, pero luego no saben explicarla, a ti compañero no te pasa eso en absoluto.

    Muchas gracias por tu aporte.

    Responder

  32. alonso

    Muy bueno el detalle de Jesse James… pero cesar ha planteado una cuestion que no he visto que la hayan respondido y la cual me esta sucediendo a mi tambien: es con respecto al casting, tambien obtengo el mismo error:

    Product prod = (Product) itr.next();

    java.lang.ClassCastException: [java.lang.Object; cannot be cast to myapp.Product]

    He encontrado un par de foros donde se toca el tema pero no encuentro solucion ya voy por el segundo dia de no poder resolver esto…

    Gracias por el consejo

    Responder

  33. david

    Intereseante la informacion,me va a ser de gran utilidad

    Responder

  34. abel

    hola:

    estoy trabajando con la version net de hibernate, llamada nhibernate, parecio facil al inicio y rapido con sus save y saveorupdate para guardar datos…

    pero es un framework muy malo (como sea que se llame), en sus proyectos no lo usen, bueno si no quieren borrar en cascada o no trabajaran con procedimientos almacenados, la verdad… igual es pesimamente malo…

    el asunto es que los procedimientos hay que mapearlos a mano, los delete en cascada siempre dan problemas al crearse… esto te hace gastar un monton de tiempo en depuracion, cosa que nhibernate deberia ahorrar (tiempo), por otro lado todo se trabaja con objetos… hasta las claves foraneas… ojala no tengas un valor de base de datos que sea not null por que solo se cae sin avisar exactamente el error si tienes algun campo asi y va algun null… y olvidense del limite de datos que tiene, si rescatan mas de 1000 filas de una tabla con muchas filas en una consulta… tampoco pueden mapearlo facilmente para reporting services y hacer informes con ello.

    conclusion… pesima herramienta, que en vez de hacer tu desarrollo mas facil, lo hace mas lento y dificil.

    Responder

  35. […] nuestra aplicación usando JSP, Servlets, JDBC, Hibernate, o cualquier otra tecnología que nos […]

    Responder

  36. badguy

    De todos los anteriores posts, me quedo con el de EDS_jorge, que con una sola pregunta daba en el clavo: “¿Alguien puede darme alguna ventaja real del uso de Hibernate sobre JDBC?”.

    Con mi experiencia puedo decir que a mí nada más que me ha aportado problemas. No digo que no hayan aplicaciones gigantescas, que tiren de más de una BBDD, que requieran “todo eso” que aporta el framework. Pero la verdad es que me han impuesto usarlo en un proyecto que a priori parecía bastante simple (una web con Struts, Spring e Hibernate) y no vean la lata que nos ha dado.

    Básicamente dejamos de usar el conocido JDBC (qué no sé por qué lo pintan de complejo… ¿?… te conectas a la BBDD y haces las consultas. Nada más, con transacciones o sin ellas) para usar un desconocido Hibernate. A la larga nos dimos cuenta de que a veces el framework toma sus propias decisiones en cuando a modificar las consultas, o según el tipo de relación, a hacer guardados automáticos de los objetos. Una verdadera pena.

    Obviamente no soy un experto en Hibernate, pero sólo quiero decir que ni JDBC es tan malo malísimo, ni Hibernate es la panacea!

    Saludos.

    Responder

  37. gjisrngjkfm

    Responder

  38. gjisrngjkfm

    Responder

  39. ghjkgdh

    khgdk

    Responder

  40. Muy bueno aclare muchas dudas que tenia =D
    Gracias amigo!!

    Responder

  41. cesar

    como saco una consulta de dos tablas y las meto en un objeto que no sea el .class de la tabla que se define si no en otro diferente ya que cuando ejecuto la consulta y le paso la lista al objeto no me trae los metadata y no los relaciona correctamente con el objeto

    Responder

  42. JuanK

    Muchas Gracias, súper util y aclarativo

    Responder

  43. marco

    alguien tiene un demo de hibernate con sql , aun estoy en la universidad y aun no me corre el mapeo quisiera ayuda por favor!

    Responder

  44. Magnolia

    Grasias por la info me es de mucha utilidad

    Responder

  45. Paloma

    Hola pues antes que nada, quisiera conocer a profundidad sobre hibernate, debido a que estoy haciendo mi tesis, y lo requiero, alguien me podria decir de acuerdo a su experiencia las ventajas y desventajas, y los posibles errores que puede generar el relacionar Java con Postgres.
    Espero sus respuestas…
    un saludo para todos
    que esten bien…
    saludos
    xao

    Responder

  46. fernando

    Ando trabajando con hibernate y en particular me gusta trabajar con ¨criteria¨, pero me ha surgido una duda, que sucederá al ejecutar una criteria la cual espere como valor un string y esta sea una cosulta, ¿se ejecutará la cunsulta?

    Responder

  47. buen resumen, gracias.

    Responder

  48. Pablo

    Me gusto mas el tutorial para empezar struts, lo hace mas paso a paso, podrias poner como integro Hibernate a partir del otro tutorial??

    Responder

  49. Johanna

    Los que tenian el problema de [Ljava.lang.Object; cannot be cast to … ya lo pudieron resolver???, tengo el mismo problema, lo raro es que si puedo insertar asi que supongo que el mapping esta bien. Alguien Help!!!! =(

    Responder

  50. Ricardo Bullanguero

    Me fue muy util tu explicacion para aclarar unos conceptos sobre hibernate q no los tenia bien claros…
    Te felicito, muy bien explicado

    Responder

Deja un comentario