Hibernate: SQL vs HQL con Session Cache

10/06/2016

hibernate_logo

Cuidado con usar SQL Queries con Hibernate

Como nuevo usuario de Hibernate, te puede sorprender agradablemente ver que soporta la ejecución de consultas SQL mediante el método createSQLQuery() del objeto Session de Hibernate.

Inicialmente parece beneficioso utilizar las viejas y sencillas sentencias SQL para generar las consultas en tus DAO’s. Después de todo, ya conoces SQL, así que porque perder el tiempo aprendiendo HQL (Hibernate Query Language) o el Hibernate Criteria API. Además, con SQL podemos probar fácilmente las consultas en herramientas de edición de base de datos como DBVisualizer y en el caso “raro” de que lo pudiera necesitar, un DBA no familiarizado con Hibernate podría mantener y mejorar mis consultas de un modo sencillo.

Parece la solución.

Sin embargo, si te paras a analizar un poco en profundidad el tema, cambiarás de opinión.

Solamente desde el punto de vista de la Orientación a Objetos existen muchas razones para evitar el uso de SQL. Sin embargo los argumentos acerca de esto no los vamos a contar aquí.

El principal punto de vista en el que nos vamos a centrar aquí es que:

El SQLQuery de Hibernate se salta la Caché de la Sesión de Hibernate y SOLAMENTE consulta contra la base de datos.

Esto quiere decir que si realizar una consulta SQL a la base de datos en la misma transacción en la que acabas de hacer un guardado y/o actualización, los objetos guardados/actualizados en la Caché de la Sesión de Hibernate no se incluirán en el resultado de la SQL.

Por este mismo motivo, HQL y las consultas de Hibernate Criteria comprueban la Cache de Sesión antes de ejecutar la consulta. Si existen objetos contra los que la consulta HQL se puedan ejecutar, Hibernate hará un flush de la Cache a la base de datos.

Esencialmente esto quiere decir que, al contrario que SQLQuery:

HQL y la consultas de Hibernate Criteria SIEMPRE incluirán los objetos de la Caché de Sesión automáticamente.

Para ilustrar el funcionamiento aquí tenemos un ejemplo:

SQL_SessionCache_med

HQL_SessionCache_med

NOTAS

  1. Como aparece en el diagrama SQLQuery, realmente puedes forzar manualmente a Hibernate a que haga flush de la caché ejecutando session.flush(). Esto te obligaría a ejecutar esta línea antes de cada SQLQuery que ejecutes. Esto es:
        session.flush();
        List result = session.createSqlQuery("select name from user where name = :userName")
           .setParameter("userName", user.getName())
           .list();
    

    Sin embargo esto tiene dos grandes inconvenientes:

    • Te puedes olvidar accidentalmente de hacerlo, dejando tu aplicación en un estado incoherente.
    • sessión.flush() es una operación costosa. Usando HQL y Criteria, Hibernate puede decidir si necesita o no hacer flush. Por tanto se evitan flush’s innecesarios.
  2. JUnit test
    No hace falta mencionar que el código de los diagramas de ejemplo son tests JUnit. Inicializando el mecanismo de transacciones y la sesión de caché de Hibernate podremos testar nuestro código DAO sin cambiar realmente el estado de nuestra base de datos. Al final del test podemos simplemente hacer rollback de la transacción y deshacer cualquier actualización que hayamos hecho.

via

A pesar de todos los inconvenientes “necesito” usar una SQLQuery

Si a pesar de todo lo anterior sigues “necesitando” ejecutar una SQLQuery, te contaré que existe una alternativa mejor a la invocación explicita de session.flush(). Se trata de utilizar el método addSynchronizedQuerySpace() de SQLQuery.

Si, por ejemplo, tenemos el siguiente código:

session.createSqlQuery("select name from user where name = :userName")

lo sustituiríamos por este otro:

session.createSqlQuery("select name from user where name = :userName")
.addSynchronizedQuerySpace( "user" )

De modo que addSynchronizedQuerySpace( “user” ) lo que hace es indicar a Hibernate que la consulta utiliza la tabla “user”. Esto hace que Hibernate pueda hacer auto flush de todos los cambios pendientes para entidades mapeadas con dicha tabla.

Algunos enlaces de interés

The dark side of Hibernate AUTO flush
10.10. Flushing the Session

Responder

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Cerrar sesión / Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Cerrar sesión / Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Cerrar sesión / Cambiar )

Google+ photo

Estás comentando usando tu cuenta de Google+. Cerrar sesión / Cambiar )

Conectando a %s

A %d blogueros les gusta esto: