Buenas prácticas en el uso de Hibernate

LIBP-0046 (Libro de pautas)

Se deben tener en cuenta las siguientes recomendaciones para mejorar el uso de Hibernate como motor de persistencia.

Pautas

TítuloCarácter
Usar un pool de conexionesObligatoria
Configurar el "pool" de conexionesObligatoria
Selección de pool de conexionesRecomendada
Conexiones JDBC propiasObligatoria
Implementar una NamingStrategyObligatoria
Implementar los métodos equals() y hashCode()Recomendada
Tratamiento de las excepcionesObligatoria
Excepciones producidas por los DAOObligatoria
Anotaciones compatibles con JPAObligatoria
Anotaciones propiasObligatoria

Usar un pool de conexiones

Utilizar un pool de conexiones para interactuar con la base de datos.

Por lo general, no es aconsejable crear una conexión cada vez que se interaccione con la base de datos. Para evitar esta situación, las aplicaciones Java, suelen utilizar un pool de conexiones. Cada subproceso de la aplicación que realiza solicitudes sobre la base de datos, solicita una conexión al pool, devolviéndola cuando todas las operaciones SQL han sido sido ejecutadas.

El pool mantiene las conexiones y minimiza el coste de abrir y cerrar conexiones. Hay tres razones para el uso de un pool:

  • La adquisición de una nueva conexión es costosa. Algunos sistemas de gestión de base de datos incluso inician un proceso completamente nuevo en el servidor para cada conexión.
  • Optimiza el uso de conexiones inactivas o desconectar si no hay solicitudes.
  • Almacena instrucciones en caché para posteriores peticiones.

Configurar el "pool" de conexiones

No usar el pool de conexiones integrado en Hibernate en entornos de producción

El pool de conexiones integrado en Hibernate no esta pensado de ninguna manera para su uso en producción, ni siquiera para entornos de pruebas de rendimiento, ya que carece de diversas características disponibles en cualquier pool de conexiones apropiado para estos entornos.

En su lugar se recomienda la utilización de C3P0 o Proxoll.

Selección de pool de conexiones

Utilizar C3P0 o Proxool como pool de conexiones en Hibernate

C3P0 es un pool de conexiones JDBC de código abierto distribuido junto con Hibernate en el directorio lib. Hibernate utilizará su org.hibernate.connection.C3P0ConnectionProvider para el pooling de conexiones si se establecen las propiedades hibernate.c3p0.*.

Otra opción sería utilizar Proxool como pool de conexiones. Para ello, debe configurarse el hibernate.properties incluído en el paquete.

Conexiones JDBC propias

No administrar nuestras propias conexiones JDBC

Hibernate permite gestionar de una forma personalizada las conexiones JDBC. Este enfoque debe considerarse como un último recurso. Si no puede usar las conexiones ya provistas, considere la posibilidad de implementar su propia clase org.hibernate.connection.ConnectionProvider.

Implementar una NamingStrategy

Especificar estándares de nombramiento para objetos de la base de datos utilizando la interfaz org.hibernate.cfg.NamingStrategy

La interfaz org.hibernate.cfg.NamingStrategy le permite especificar un estándar de nombramiento para objetos de la base de datos y los elementos del esquema.

Puede proporcionar reglas para generar automáticamente identificadores de la base de datos a partir de identificadores JDBC o para procesar nombres "lógicos" de columnas y tablas dadas en el archivo de vínculos de nombres "físicos" de columnas y tablas. Esta funcionalidad ayuda a reducir la verborragia del documento de vinculación, eliminando ruidos repetitivos (por ejemplo, prefijos TBL_). Hibernate utiliza una estrategia por defecto bastante mínima.

org.hibernate.cfg.ImprovedNamingStrategy es una estrategia incorporada que puede ser un punto de partida útil para algunas aplicaciones.

Implementar los métodos equals() y hashCode()

Se recomienda sobreescribir los métodos equals() y hashCode()

Tiene que sobrescribir los métodos equals() y hashCode() si:

  • Piensa poner instancias de clases persistentes en un Set (la forma recomendada de representar asociaciones multivaluadas); y
  • Piensa utilizar reasociación de instancias separadas.

Hibernate garantiza la equivalencia de identidad persistente (fila de base de datos) y de identidad Java solamente dentro del ámbito de una sesión en particular. De modo que en el momento en que mezcla instancias recuperadas en sesiones diferentes, tiene que implementar equals() y hashCode() si desea tener una semántica significativa para Sets.

La forma más obvia es implementar equals()/hashCode() comparando el valor identificador de ambos objetos. Si el valor es el mismo, ambos deben ser la misma fila de la base de datos ya que son iguales. Si ambos son agregados a un Set, sólo tendremos un elemento en el Set. Desafortunadamente, no puede utilizar este enfoque con identificadores generados. Hibernate sólo asignará valores identificadores a objetos que son persistentes; una instancia recién creada no tendrá ningún valor identificador. Además, si una instancia no se encuentra guardada y está actualmente en un Set, al guardarla se asignará un valor identificador al objeto. Si equals() y hashCode() están basados en el valor identificador, el código hash podría cambiar, rompiendo el contrato del Set. Este no es un problema de Hibernate, sino de la semántica normal de Java de identidad de objeto e igualdad.

Tratamiento de las excepciones

No tratar las excepciones como recuperables

Cuando ocurra una excepción, debemos deshacer la operación y cerrar la sesión. Hibernate no puede garantizar que la memoria represente fielmente el estado. Como caso especial de esto, no utilizar Session.load para determinar si una instancia existe en la base de datos, usar Session.get o una consulta en su lugar.

Excepciones producidas por los DAO

Jerarquizar las excepciones producidas por los DAO

Se recomienda usar un modelo de Excepciones DAO jerárquico propio, tal como por ejemplo: DAOException, DAOIdentificadorNoInformadoException, DAOIntegrityException, DAOValidacionException, DAOContratViolationException, DAORegistroNoEncontradoException… En la práctica se ha demostrado que es más práctico trabajar con un modelo de excepciones de este tipo que con un modelo de excepciones ligado al modelo (UsuarioDAOException, PagoDAOException,...).

Anotaciones compatibles con JPA

Utilizar anotaciones compatibles con JPA

Las anotaciones compatibles con JPA son aquellas etiquetas que dicta la especificación JPA. Nada raro, si tenemos en cuenta que Hibernate es un proveedor de JPA. Todas estas se encuentran en el paquete javax.persistence.

Anotaciones propias

Usar anotaciones propias cuando no existan anotaciones compatibles con JPA

Las anotaciones propias son aquellas anotaciones que Hibernate proporciona para configurar características propias. Con estas anotaciones podemos hacer casi todo los que está a nuestro alcance con los ficheros XML. No tienen nada que ver con las especificaciones de Java.