JPA e Hibernate - Criterios vs. JPQL o HQL

295

¿Cuáles son los pros y los contras de usar Criteria o HQL ? Criteria API es una buena forma orientada a objetos para expresar consultas en Hibernate, pero a veces Criteria Queries es más difícil de entender / construir que HQL.

¿Cuándo utiliza Criterios y cuándo HQL? ¿Qué prefieres en qué casos de uso? ¿O es solo una cuestión de gustos?

Cretzel
fuente
La respuesta correcta sería "depende del caso de uso".
Hace
¿Y qué hay de esta herramienta ? Permite construir consultas comunes de forma objetiva: cláusula protegida select () {return em.select ("DISTINCT i") .from (this.getName (), "i") .joinFetch ("i.locale lf") } public T findBySlug (slug de cadena) {return (T) this.select () .join ("i.locale l"); .where ("l.slug =?", slug) .fetchSingle (); }
Vojtěch
1
Definición de una pregunta basada en la opinión, sin embargo, las personas no han aprovechado la oportunidad para cerrarla ... según las preguntas frecuentes del sitio

Respuestas:

212

Principalmente prefiero las consultas de criterios para consultas dinámicas. Por ejemplo, es mucho más fácil agregar algunos pedidos dinámicamente o dejar algunas partes (por ejemplo, restricciones) fuera, dependiendo de algún parámetro.

Por otro lado, estoy usando HQL para consultas estáticas y complejas, porque es mucho más fácil de entender / leer HQL. Además, creo que HQL es un poco más potente, por ejemplo, para diferentes tipos de unión.

Cretzel
fuente
13
Además, aunque Criteria parece un poco más seguro para escribir, lo único que puede hacerte sentir seguro es la prueba.
¿Hay buenos ejemplos que muestren por qué HQL es mejor que los criterios api en ciertos casos? Leí el final de un blog, pero no entendí nada. Le agradecería si pudiera ayudar. Gracias. Enlace - javalobby.org/articles/hibernatequery102
Erran Morad
Todas las razones anteriores: también prefiero Criterios a HQL porque es más seguro para el programador, lo que disminuye los errores de codificación: la compilación en la cadena HQL no está validada.
nuno
Sin embargo, está el problema de recuperar entidades distintas mientras paginas. Al hacer esto, elegiría HQL para evitar problemas ...
Anthony Webster
El uso de la consulta de criterios con un metamodelo para los nombres de columna ayuda durante la refactorización a no romper nada y con un simple comando de un IDE moderno para cambiar el nombre de todas las apariciones en el código.
Massimo
92

Hay una diferencia en términos de rendimiento entre HQL y criterioQuery, cada vez que activa una consulta usando criterioQuery, crea un nuevo alias para el nombre de la tabla que no se refleja en la última caché consultada para ninguna base de datos. Esto lleva a una sobrecarga de compilar el SQL generado, lo que lleva más tiempo ejecutarlo.

Con respecto a las estrategias de obtención [http://www.hibernate.org/315.html]

  • Criteria respeta la configuración de pereza en sus asignaciones y garantiza que se cargue lo que desea cargar. Esto significa que una consulta de Criterios podría dar como resultado varias instrucciones SELECT inmediatas de SQL para obtener el subgrafo con todas las asociaciones y colecciones mapeadas no perezosas. Si desea cambiar el "cómo" e incluso el "qué", use setFetchMode () para habilitar o deshabilitar la búsqueda de combinaciones externas para una colección o asociación en particular. Las consultas de criterios también respetan por completo la estrategia de obtención (unirse vs seleccionar vs subseleccionar).
  • HQL respeta la configuración de la pereza en sus asignaciones y garantiza que se cargue lo que desea cargar. Esto significa que una consulta HQL puede generar varias sentencias SELECT inmediatas de SQL para obtener el subgrafo con todas las asociaciones y colecciones mapeadas no perezosas. Si desea cambiar el "cómo" e incluso el "qué", use LEFT JOIN FETCH para habilitar la búsqueda de unión externa para una colección en particular o una asociación de muchos a uno o uno a uno, o JOIN FETCH para habilitar búsqueda de unión interna para una asociación de muchos a uno o uno a uno no anulable. Las consultas HQL no respetan ningún fetch = "join" definido en el documento de mapeo.
Varun Mehta
fuente
1
Solo señalo a cualquiera que esté navegando. que esta respuesta es de 2008. puede que este ya no sea el caso. dimovelev.blogspot.com/2015/02/…
Amalgovinus
41

Criteria es una API orientada a objetos, mientras que HQL significa concatenación de cadenas. Eso significa que se aplican todos los beneficios de la orientación a objetos:

  1. En igualdad de condiciones, la versión OO es algo menos propensa a errores. Cualquier cadena antigua podría agregarse a la consulta HQL, mientras que solo los objetos Criteria válidos pueden convertirse en un árbol Criteria. Efectivamente, las clases de Criterios están más restringidas.
  2. Con el autocompletado, el OO es más reconocible (y, por lo tanto, más fácil de usar, al menos para mí). No necesariamente necesita recordar qué partes de la consulta van a dónde; el IDE puede ayudarlo
  3. Tampoco necesita recordar los detalles de la sintaxis (como qué símbolos van a dónde). Todo lo que necesita saber es cómo llamar a métodos y crear objetos.

Dado que HQL se parece mucho a SQL (que la mayoría de los desarrolladores ya conocen muy bien), estos argumentos de "no tener que recordar" no tienen tanto peso. Si HQL fuera más diferente, esto sería más importante.

Craig Walker
fuente
12
Estos argumentos no son válidos (con respecto a HQL). No tiene que implicar concatenación de cadenas. Que la versión OO sea menos propensa a errores no tiene fundamento. Es igualmente propenso a errores pero de un tipo diferente. El esfuerzo de saber qué métodos llamada no es muy diferente de saber qué símbolos para llamar en HQL (quiero decir, en serio, no estamos resolviendo PDE aquí.)
luis.espinal
¿Hay buenos ejemplos que muestren por qué HQL es mejor que los criterios api en ciertos casos? Leí el final de un blog, pero no entendí nada. Le agradecería si pudiera ayudar. Gracias. Enlace - javalobby.org/articles/hibernatequery102
Erran Morad
1
Las consultas con nombre HQL se compilan en el momento de la implementación y en este punto se detectan campos faltantes (¿tal vez por refactores incorrectos?). Creo que esto hace que el código sea más resistente y, de hecho, menos propenso a errores que los criterios.
narduk
El autocompletado en Criteria es prácticamente inútil porque las propiedades son solo cadenas.
Lluis Martinez
35

Usualmente uso Criterios cuando no sé qué entradas se usarán en qué datos. Como en un formulario de búsqueda donde el usuario puede ingresar cualquiera de 1 a 50 elementos y no sé qué buscarán. Es muy fácil agregar más a los criterios a medida que reviso lo que el usuario está buscando. Creo que sería un poco más problemático poner una consulta HQL en esa circunstancia. Sin embargo, HQL es genial cuando sé exactamente lo que quiero.

Arthur Thomas
fuente
1
Este es un buen comentario. Actualmente construimos cadenas HQL muy grandes para un formulario de búsqueda que contiene muchos objetos diferentes a través de combinaciones. Se ve feo. A ver si un Criterio puede limpiar eso. Interesante ...
cbmeeks
Gracias. Este es un excelente ejemplo. ¿Me puede dar un poco más?
Erran Morad
31

HQL es mucho más fácil de leer, más fácil de depurar usando herramientas como el complemento Eclipse Hibernate y más fácil de registrar. Las consultas de criterios son mejores para construir consultas dinámicas donde gran parte del comportamiento se determina en tiempo de ejecución. Si no conoce SQL, podría entender el uso de consultas de Criterios, pero en general prefiero HQL si sé lo que quiero por adelantado.

Brian Deterling
fuente
22

Los criterios son la única forma de especificar búsquedas de claves naturales que aprovechan la optimización especial en el caché de consultas de segundo nivel. HQL no tiene ninguna forma de especificar la sugerencia necesaria.

Puedes encontrar más información aquí:

Alex Miller
fuente
21

Criterios Api es uno de los buenos conceptos de Hibernate. Según mi punto de vista, estos son los pocos puntos por los cuales podemos hacer la diferencia entre HQL y Criteria Api

  1. HQL es realizar operaciones tanto selectivas como no selectivas en los datos, pero los Criterios son solo para seleccionar los datos, no podemos realizar operaciones no selectivas utilizando criterios.
  2. HQL es adecuado para ejecutar consultas estáticas, mientras que Criteria es adecuado para ejecutar consultas dinámicas
  3. HQL no admite el concepto de paginación , pero podemos lograr la paginación con Criteria.
  4. Los criterios solían tomar más tiempo para ejecutarse que HQL.
  5. Con Criteria, estamos seguros con la inyección de SQL debido a su generación dinámica de consultas, pero en HQL ya que sus consultas son fijas o parametrizadas, no hay seguridad de la inyección de SQL
Arvind
fuente
11
Un par de puntos La paginación está ahí en HQL: puede usar limit offset:rows En hql puede evitar la inyección de sql usandosetParameter
Viswanath Lekshmanan
13

Para usar lo mejor de ambos mundos, la expresividad y concisión de HQL y la naturaleza dinámica de Criteria consideran usar Querydsl .

Querydsl admite JPA / Hibernate, JDO, SQL y Collections.

Soy el mantenedor de Querydsl, por lo que esta respuesta es parcial.

Timo Westkämper
fuente
13

Para mí, Criteria es bastante fácil de entender y hacer consultas dinámicas. Pero la falla que digo hasta ahora es que carga todas las relaciones de muchos, etc., porque solo tenemos tres tipos de FetchModes, es decir, Seleccionar, Proxy y Predeterminado, y en todos estos casos carga muchos (uno puede estar equivocado si es así, ayuda Sacarme :))

El segundo problema con los Criterios es que carga el objeto completo, es decir, si solo quiero cargar EmpName de un empleado, no aparecerá este hecho, aparecerá el objeto Employee completo y puedo obtener EmpName debido a esto , realmente funciona mal en la presentación de informes . donde como HQL solo carga (no cargó asociación / relaciones) lo que desea, así que aumente el rendimiento muchas veces.

Una característica de Criteria es que lo protegerá de la inyección de SQL debido a su generación dinámica de consultas, ya que en HQL sus consultas son fijas o parametrizadas, por lo que no están a salvo de la inyección de SQL.

Además, si escribe HQL en sus archivos aspx.cs, entonces está estrechamente relacionado con su DAL.

En general, mi conclusión es que hay lugares donde no puedes vivir sin HQL como informes, así que úsalos de otra manera. Los criterios son más fáciles de administrar.

Zafar
fuente
13
HQL NO es seguro para inyección SQL
Varun Mehta
Creo que Criteria no es seguro para la inyección. Vea mi publicación aquí: stackoverflow.com/questions/6746486/…
Mister Smith
44
HQL IS sql inyección segura agregando 'setParameter'
Javatar
2
@Zafar: puede seleccionar solo ciertas propiedades de una entidad usando proyecciones
Răzvan Flavius ​​Panda
@Zafar puede configurar la proyección en la consulta de criterios para seleccionar columnas particulares. Puede recuperar EmpName, no es necesario recuperar el objeto completo.
Khatri
12

Criterios API

Criteria API es más adecuada para consultas generadas dinámicamente. Entonces, si desea agregar filtros de cláusula WHERE, cláusulas JOIN o variar la cláusula ORDER BY o las columnas de proyección, entonces la API Criteria puede ayudarlo a generar la consulta dinámicamente de una manera que también evite los ataques de inyección SQL .

Por otro lado, las consultas de Criterios son menos expresivas e incluso pueden conducir a consultas SQL muy complicadas e ineficientes, como se explica en este artículo .

JPQL y HQL

JPQL es el lenguaje de consulta de entidad estándar JPA, mientras que HQL extiende JPQL y agrega algunas características específicas de Hibernate.

JPQL y HQL son muy expresivos y se parecen a SQL. A diferencia de Criteria API, JPQL y HQL facilitan la predicción de la consulta SQL subyacente que genera el proveedor JPA. También es mucho más fácil revisar las consultas HQL de uno que los Criterios.

Vale la pena señalar que seleccionar entidades con JPQL o Criteria API tiene sentido si necesita modificarlas. De lo contrario, una proyección DTO es una opción mucho mejor.

Conclusión

Si no necesita variar la estructura de consulta de la entidad, use JPQL o HQL. Si necesita cambiar los criterios de filtrado o clasificación o cambiar la proyección, use Criteria API.

Sin embargo, solo porque esté usando JPA o Hibernate, no significa que no deba usar SQL nativo. Las consultas SQL son muy útiles y JPQL y Criteria API no son un reemplazo para SQL. Consulte este artículo para obtener más detalles sobre este tema.

Vlad Mihalcea
fuente
11

Para mí, la mayor victoria en Criteria es la API de ejemplo, donde puede pasar un objeto e hibernar generará una consulta basada en esas propiedades del objeto.

Además de eso, la API de criterios tiene sus peculiaridades (creo que el equipo de hibernación está reelaborando la API), como:

  • un criterio.createAlias ​​("obj") fuerza una unión interna en lugar de una posible unión externa
  • no puedes crear el mismo alias dos veces
  • algunas cláusulas sql no tienen una contraparte de criterios simples (como una subselección)
  • etc.

Tiendo a usar HQL cuando quiero consultas similares a sql (eliminar de usuarios donde status = 'bloqueado'), y tiendo a usar criterios cuando no quiero usar el agregado de cadenas.

Otra ventaja de HQL es que puede definir todas sus consultas de antemano e incluso externalizarlas a un archivo más o menos.

Miguel Ping
fuente
9

Los criterios de la API proporcionan una característica distinta que ni SQL ni HQL proporcionan. es decir. permite la verificación en tiempo de compilación de una consulta.

usuario1165443
fuente
7

Al principio, utilizamos principalmente Criterios en nuestra aplicación, pero después de que se reemplazó con HQL debido a problemas de rendimiento.
Principalmente estamos usando consultas muy complejas con varias combinaciones que conducen a múltiples consultas en Criteria pero están muy optimizadas en HQL.
El caso es que usamos solo varias propiedades en un objeto específico y no en objetos completos. Con Criteria, el problema también era la concatenación de cadenas.
Digamos que si necesita mostrar el nombre y el apellido del usuario en HQL, es bastante fácil, (name || ' ' || surname)pero en Crteria esto no es posible.
Para superar esto, utilizamos ResultTransormers, donde había métodos en los que se implementaba dicha concatenación para obtener el resultado necesario.
Hoy usamos principalmente HQL así:

String hql = "select " +
            "c.uuid as uuid," +
            "c.name as name," +
            "c.objective as objective," +
            "c.startDate as startDate," +
            "c.endDate as endDate," +
            "c.description as description," +
            "s.status as status," +
            "t.type as type " +
            "from " + Campaign.class.getName() + " c " +
            "left join c.type t " +
            "left join c.status s";

Query query =  hibernateTemplate.getSessionFactory().getCurrentSession().getSession(EntityMode.MAP).createQuery(hql);
query.setResultTransformer(Transformers.ALIAS_TO_ENTITY_MAP);
return query.list();

en nuestro caso, los registros devueltos son mapas de propiedades necesarias.

Bojan Kraut
fuente
1
Con Criteria puedes usar org.hibernate.criterion.CriteriaSpecification.ALIAS_TO_ENTITY_MAP
AA.
Devolver una lista de mapas en mi experiencia tiene un rendimiento muy malo. Prefiero devolver una lista de matrices de objetos o una lista de beans (siempre puede definir un bean que se adapte a su conjunto de resultados específico).
Lluis Martinez
7
  • HQL es realizar operaciones tanto selectivas como no selectivas en los datos, pero los Criterios son solo para seleccionar los datos, no podemos realizar operaciones no selectivas utilizando criterios
  • HQL es adecuado para ejecutar consultas estáticas, mientras que Criteria es adecuado para ejecutar consultas dinámicas
  • HQL no admite el concepto de paginación, pero podemos lograr la paginación con Criteria
  • Los criterios solían tomar más tiempo para ejecutarse que HQL
  • Con Criteria, estamos seguros con la inyección de SQL debido a su generación dinámica de consultas, pero en HQL ya que sus consultas son fijas o parametrizadas, no hay seguridad de la inyección de SQL.

fuente

Premraj
fuente
Para aclarar, las consultas de criterios que utilizan la API de criterios de Hibernate pueden estar disponibles para consultas, pero las consultas de criterios JPA cubren selecciones, actualizaciones y eliminaciones. Ver CriteriaUpdate<T>y CriteriaDelete<T>para referencia.
Naros
5

Consulta de criterios para dinámicamente podemos construir consultas basadas en nuestras entradas ... En el caso de la consulta Hql es la consulta estática una vez que construimos no podemos cambiar la estructura de la consulta.

usuario1679378
fuente
2
No tan. Con HQL puede establecer propiedades con el identificador ':' y luego reemplazar esas propiedades con valores únicos. Por ejemplo, Query q = session.createQuery ("SELECT: aValue FROM my_table"); y luego q.setParameter ("aValue", "some_column_name");
MattC
@MattC En su ejemplo, está cambiando los valores de los parámetros, no la estructura de la consulta.
Zar
4

No quiero patear un caballo muerto aquí, pero es importante mencionar que las consultas de Criterios ahora están en desuso. Utiliza HQL.

Eskir
fuente
1

También prefiero las consultas de criterios para consultas dinámicas. Pero prefiero hql para eliminar consultas, por ejemplo, si elimina todos los registros de la tabla secundaria para la identificación principal 'xyz', HQL lo logra fácilmente, pero para los criterios API primero debemos disparar n número de consultas de eliminación donde n es el número de hijos tabla de registros.

Punit Patel
fuente
0

La mayoría de las respuestas aquí son engañosas y mencionan que Criteria Queriesson más lentas que HQL, lo que en realidad no es el caso.

Si profundiza y realiza algunas pruebas, verá que las consultas de criterios funcionan mucho mejor que el HQL normal .

Y también con Criteria Query obtienes control orientado a objetos que no existe con HQL .

Para más información lea esta respuesta aquí .

Pritam Banerjee
fuente
0

Hay otra manera Terminé creando un analizador HQL basado en la sintaxis original de hibernación, por lo que primero analiza el HQL y luego puede inyectar dinámicamente parámetros dinámicos o agregar automáticamente algunos filtros comunes para las consultas HQL. ¡Funciona muy bien!

Wallace Peng
fuente
0

Esta publicación es bastante antigua. La mayoría de las respuestas hablan de criterios de Hibernate, no de criterios JPA. JPA 2.1 agregó CriteriaDelete / CriteriaUpdate y EntityGraph que controla exactamente qué buscar. Criterios API es mejor ya que Java es OO. Por eso se crea JPA. Cuando se compila JPQL, se traducirá al árbol AST (modelo OO) antes de traducirse a SQL.

Día soleado
fuente
-3

HQL puede causar problemas de seguridad como la inyección SQL.

Emad Aghayi
fuente
11
Estos problemas no son causados ​​por HQL, sino por la falta de comprensión de las prácticas básicas de desarrollo de software. También puedo crear código propenso a los ataques de inyección SQL con criterios de API.
Jens Schauder
1
Es como decir "consultar un RDBMS desde Java puede causar problemas de seguridad de inyección SQL": D
Czar