JPA e Hibernate - Critérios vs. JPQL ou HQL


295

Quais são os prós e os contras do uso de Critérios ou HQL ? A API de critérios é uma boa maneira orientada a objetos para expressar consultas no Hibernate, mas às vezes as consultas de critérios são mais difíceis de entender / criar do que o HQL.

Quando você usa Critérios e quando HQL? O que você prefere em quais casos de uso? Ou é apenas uma questão de gosto?


A resposta correta seria 'depende do caso de uso'.
Hace

E quanto a essa ferramenta ? Permite construir consultas comuns de uma maneira objeto: Cláusula protegida select () {return em.select ("DISTINCT i"). De (this.getName (), "i") .joinFetch ("i.locale lf") } public T findBySlug (String slug) {return (T) this.select () .join ("i.locale l"); .where ("l.slug =?", lesma) .fetchSingle (); }
Vojtěch

1
Definição de uma pergunta baseada em opinião, mas as pessoas não aproveitaram a oportunidade para fechá-la ... de acordo com as perguntas frequentes do site

Respostas:


212

Eu prefiro consultas de critério para consultas dinâmicas. Por exemplo, é muito mais fácil adicionar alguns pedidos dinamicamente ou deixar algumas peças (por exemplo, restrições) de fora, dependendo de algum parâmetro.

Por outro lado, estou usando o HQL para consultas estáticas e complexas, porque é muito mais fácil entender / ler o HQL. Além disso, acho que o HQL é um pouco mais poderoso, por exemplo, para diferentes tipos de junção.


13
Além disso, embora os Critérios pareçam um pouco mais seguros quanto ao tipo, a única coisa que pode fazer você se sentir seguro é testar.

Existem bons exemplos que mostram por que o HQL é melhor que o critério API em certos casos? Eu li o final de um blog, mas não entendi nada. Agradeceria se você pudesse ajudar. Obrigado. Link - javalobby.org/articles/hibernatequery102
Erran Morad

Todas as razões acima - também prefiro Critérios ao HQL, porque é mais seguro para o programador, diminuindo os erros de codificação - a compilação na sequência HQL não é validada.
Nuno 31/07

No entanto, há o problema de recuperar entidades distintas enquanto pagina. Ao fazer isso eu escolheria HQL a questões Evitar ...
Anthony Webster

o uso da consulta de critérios com um metamodelo para os nomes das colunas ajuda durante a refatoração a não quebrar nada e com um simples comando de um IDE moderno para renomear todas as ocorrências no código.
Massimo

92

Há uma diferença em termos de desempenho entre HQL e criterQuery, sempre que você dispara uma consulta usando o critérioQuery, ele cria um novo alias para o nome da tabela que não reflete no último cache consultado para nenhum banco de dados. Isso leva a uma sobrecarga de compilação do SQL gerado, levando mais tempo para ser executado.

Sobre estratégias de busca [http://www.hibernate.org/315.html]

  • Os critérios respeitam as configurações de preguiça nos seus mapeamentos e garantem que o que você deseja carregar seja carregado. Isso significa que uma consulta de Critérios pode resultar em várias instruções SELECT imediatas do SQL para buscar o subgráfico com todas as associações e coleções mapeadas não preguiçosas. Se você deseja alterar o "como" e até o "o quê", use setFetchMode () para ativar ou desativar a busca de junção externa para uma coleção ou associação específica. As consultas de critério também respeitam completamente a estratégia de busca (junção x seleção x subseleção).
  • O HQL respeita as configurações de preguiça nos seus mapeamentos e garante que o que você deseja carregar seja carregado. Isso significa que uma consulta HQL pode resultar em várias instruções SELECT imediatas do SQL para buscar o subgráfico com todas as associações e coleções mapeadas não preguiçosas. Se você quiser alterar o "como" e até o "o quê", use LEFT JOIN FETCH para ativar a busca de junção externa para uma coleção específica ou associação anulável de muitos para um ou um para um ou um JOIN FETCH para ativar busca de junção interna para uma associação muitos-para-um ou um-para-um não-anulável. As consultas HQL não respeitam nenhuma busca = "associação" definida no documento de mapeamento.

1
Apenas apontando para quem está navegando. que esta resposta é de 2008. pode não ser mais esse o caso. dimovelev.blogspot.com/2015/02/…
Amalgovinus

41

Critérios é uma API orientada a objetos, enquanto HQL significa concatenação de cadeias. Isso significa que todos os benefícios da orientação a objetos se aplicam:

  1. Tudo o resto é igual, a versão OO é um pouco menos propensa a erros. Qualquer cadeia antiga pode ser anexada à consulta HQL, enquanto apenas objetos Criteria válidos podem transformá-la em uma árvore de Critérios. Efetivamente, as classes de Critérios são mais restritas.
  2. Com o preenchimento automático, o OO é mais detectável (e, portanto, mais fácil de usar, pelo menos para mim). Você não precisa necessariamente lembrar quais partes da consulta vão para onde; o IDE pode ajudá-lo
  3. Você também não precisa se lembrar dos detalhes da sintaxe (como quais símbolos vão para onde). Tudo que você precisa saber é como chamar métodos e criar objetos.

Como o HQL é muito parecido com o SQL (que a maioria dos desenvolvedores já conhece muito bem), esses argumentos "não precisam se lembrar" não têm tanto peso. Se o HQL fosse mais diferente, isso seria mais importante.


12
Esses argumentos não retêm água (com relação ao HQL). Não precisa envolver concatenação de cadeias. O fato de a versão OO ser menos propensa a erros não tem fundamento. É igualmente propenso a erros, mas de um tipo diferente. O esforço de saber quais métodos a chamada não é muito diferente de saber quais símbolos de chamar HQL (quero dizer, seriamente, não estamos resolvendo PDEs aqui.)
luis.espinal

Existem bons exemplos que mostram por que o HQL é melhor que o critério API em certos casos? Eu li o final de um blog, mas não entendi nada. Agradeceria se você pudesse ajudar. Obrigado. Link - javalobby.org/articles/hibernatequery102
Erran Morad

1
As consultas nomeadas HQL são compiladas no tempo de implantação e, neste momento, os campos ausentes (talvez para refatores ruins?) São detectados. Eu acho que isso torna o código mais resistente e de fato menos propenso a erros que os critérios.
Narduk

O preenchimento automático em Critérios é praticamente inútil porque as propriedades são apenas cadeias de caracteres.
Lluis Martinez

35

Normalmente, uso Critérios quando não sei quais serão as entradas em quais dados. Como em um formulário de pesquisa onde o usuário pode inserir de 1 a 50 itens e não sei o que ele estará procurando. É muito fácil anexar mais aos critérios à medida que passo verificando o que o usuário está procurando. Eu acho que seria um pouco mais problemático colocar uma consulta HQL nessa circunstância. HQL é ótimo quando eu sei exatamente o que eu quero.


1
Este é um bom comentário. Atualmente, construímos cadeias HQL muito grandes para um formulário de pesquisa que contém muitos objetos diferentes por meio de junções. Parece feio. Indo para ver se um critério pode limpar isso. Interessante ...
cbmeeks

Obrigado. Este é um excelente exemplo. Você pode me dar um pouco mais?
Erran Morad

31

O HQL é muito mais fácil de ler, mais fácil de depurar usando ferramentas como o plug-in Eclipse Hibernate e mais fácil de registrar. As consultas de critério são melhores para criar consultas dinâmicas em que muito do comportamento é determinado em tempo de execução. Se você não conhece SQL, eu poderia entender usando consultas de Critérios, mas no geral prefiro HQL se souber o que quero antecipadamente.



21

Critérios A API é um dos bons conceitos do Hibernate. de acordo com o meu ponto de vista, esses são os poucos pontos pelos quais podemos fazer a diferença entre HQL e Critérios API

  1. O HQL é executar operações de seleção e não seleção nos dados, mas Critérios é apenas para selecionar os dados, não podemos executar operações de não seleção usando critérios.
  2. HQL é adequado para executar Consultas Estáticas, enquanto Critérios é adequado para executar Consultas Dinâmicas
  3. O HQL não suporta o conceito de paginação , mas podemos obter a paginação com Critérios.
  4. Os critérios costumavam levar mais tempo para serem executados que o HQL.
  5. Com os Critérios, estamos seguros com o SQL Injection devido à sua geração dinâmica de consultas, mas no HQL, como suas consultas são fixas ou parametrizadas, não há segurança do SQL Injection

11
limit offset:rows Alguns pontos A paginação existe no HQL: você pode usar No hql, você pode evitar a injeção de sql usandosetParameter
Viswanath Lekshmanan

13

Para usar o melhor dos dois mundos, a expressividade e concisão do HQL e a natureza dinâmica dos Critérios consideram o uso do Querydsl .

Querydsl suporta JPA / Hibernate, JDO, SQL e Coleções.

Eu sou o mantenedor do Querydsl, então essa resposta é tendenciosa.


13

Para mim, os critérios são bastante fáceis de entender e fazer consultas dinâmicas. Mas a falha que eu digo até agora é que ele carrega todas as relações etc, porque temos apenas três tipos de FetchModes, isto é, Select, Proxy e Default e, em todos esses casos, carrega muitos (pode ser que eu esteja errado, se for o caso) estou fora :))

A segunda questão com os Critérios é que ele carrega o objeto completo, ou seja, se eu quiser carregar o EmpName de um funcionário, ele não cria esse instante, ele cria o objeto Employee completo e posso obter o EmpName por causa disso, ele realmente funciona mal em relatórios . onde o HQL apenas carrega (não carrega associação / relações) o que você deseja, para aumentar o desempenho muitas vezes.

Um recurso dos Critérios é que ele protegerá você do SQL Injection por causa de sua geração dinâmica de consultas, onde, no HQL, suas consultas são fixas ou parametrizadas, portanto, não são seguras do SQL Injection.

Além disso, se você escrever HQL em seus arquivos aspx.cs, estará fortemente associado ao seu DAL.

No geral, minha conclusão é que existem lugares em que você não pode viver sem o HQL como relatórios, portanto, use-os, caso contrário, os critérios são mais fáceis de gerenciar.


13
O HQL NÃO é seguro para injeção de SQL #
Varun Mehta

Eu acho que Critérios não é seguro para injeção. Veja meu post aqui: stackoverflow.com/questions/6746486/…
Mister Smith

4
A injeção de sql do HQL IS é segura adicionando 'setParameter'
Javatar 8/12

2
@Zafar: você pode selecionar apenas certas propriedades de uma entidade usando projeções
Răzvan Flavius ​​Panda

@ Zafar, você pode definir a projeção na consulta de critérios para selecionar colunas específicas. Você pode buscar o EmpName, não é necessário buscar o objeto completo.
Khatri

12

API de critérios

A API de critérios é mais adequada para consultas geradas dinamicamente. Portanto, se você deseja adicionar filtros da cláusula WHERE, cláusulas JOIN ou variar a cláusula ORDER BY ou as colunas de projeção, a API Criteria pode ajudá-lo a gerar a consulta dinamicamente de uma maneira que também evite ataques de injeção SQL .

Por outro lado, as consultas de Critérios são menos expressivas e podem até levar a consultas SQL muito complicadas e ineficientes, conforme explicado neste artigo .

JPQL e HQL

JPQL é a linguagem de consulta de entidade padrão do JPA, enquanto o HQL estende o JPQL e adiciona alguns recursos específicos do Hibernate.

JPQL e HQL são muito expressivos e se assemelham a SQL. Diferentemente da Criteria API, o JPQL e o HQL facilitam a previsão da consulta SQL subjacente gerada pelo provedor JPA. Também é muito mais fácil revisar as consultas HQL de uma pessoa do que as de critério.

Vale a pena notar que selecionar entidades com JPQL ou API de critérios faz sentido se você precisar modificá-las. Caso contrário, uma projeção DTO é uma escolha muito melhor.

Conclusão

Se você não precisar alterar a estrutura de consulta da entidade, use JPQL ou HQL. Se você precisar alterar os critérios de filtragem ou classificação ou alterar a projeção, use a API de critérios.

No entanto, apenas porque você está usando JPA ou Hibernate, isso não significa que você não deve usar SQL nativo. As consultas SQL são muito úteis e a API JPQL e Criteria não substitui o SQL. Confira este artigo para obter mais detalhes sobre este tópico.



11

Para mim, a maior vitória em Critérios é a API de Exemplo, onde você pode passar um objeto e o hibernate criará uma consulta com base nessas propriedades do objeto.

Além disso, a API de critérios tem suas peculiaridades (acredito que a equipe de hibernação está reformulando a API), como:

  • um critério.createAlias ​​("obj") força uma junção interna em vez de uma possível junção externa
  • você não pode criar o mesmo alias duas vezes
  • algumas cláusulas sql não têm contrapartida de critérios simples (como uma subseleção)
  • etc.

Costumo usar o HQL quando quero consultas semelhantes ao sql (excluir de Usuários em que status = 'bloqueado') e costumo usar critérios quando não quero usar o acréscimo de cadeias.

Outra vantagem do HQL é que você pode definir todas as suas consultas com antecedência e até externalizá-las para um arquivo ou mais.


9

A API de critério fornece um recurso distinto que nem o SQL nem o HQL fornecem. ie permite a verificação do tempo de compilação de uma consulta.


7

Usamos principalmente Critérios em nosso aplicativo no início, mas depois ele foi substituído pelo HQL devido a problemas de desempenho.
Principalmente, estamos usando consultas muito complexas com várias junções, o que leva a várias consultas nos Critérios, mas é muito otimizado no HQL.
O caso é que usamos apenas várias propriedades em objetos específicos e não objetos completos. Com Critérios, o problema também era concatenação de cadeias.
Digamos que, se você precisar exibir o nome e o sobrenome do usuário no HQL, é bastante fácil, (name || ' ' || surname)mas no Crteria isso não é possível.
Para superar isso, usamos o ResultTransormers, onde havia métodos em que essa concatenação foi implementada para obter o resultado necessário.
Hoje, usamos principalmente o HQL assim:

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();

portanto, no nosso caso, os registros retornados são mapas das propriedades necessárias.


1
Com Critérios, você pode usar org.hibernate.criterion.CriteriaSpecification.ALIAS_TO_ENTITY_MAP
AA.

Retornar uma lista de mapas na minha experiência tem um desempenho muito ruim. Prefiro retornar uma lista de matrizes de objetos ou listas de beans (você sempre pode definir um bean que se adapte ao seu conjunto de resultados específico).
Lluis Martinez

7
  • HQL é executar operações de seleção e não seleção nos dados, mas Critérios são apenas para selecionar os dados, não podemos executar operações de não seleção usando critérios
  • HQL é adequado para executar Consultas Estáticas, enquanto Critérios é adequado para executar Consultas Dinâmicas
  • O HQL não suporta o conceito de paginação, mas podemos alcançar a paginação com Critérios
  • Os critérios costumavam levar mais tempo para executar que o HQL
  • Com os Critérios, estamos seguros com o SQL Injection devido à sua geração dinâmica de consultas, mas no HQL, como suas consultas são fixas ou parametrizadas, não há segurança do SQL Injection.

fonte


Para esclarecer, as consultas de critério usando a API de critérios do Hibernate podem estar disponíveis para consulta, mas as consultas de critério JPA abrangem seleções, atualizações e exclusões. Veja CriteriaUpdate<T>e CriteriaDelete<T>para referência.
Naros

5

Consulta de critérios para dinamicamente podemos construir consulta com base em nossas entradas .. No caso de consulta Hql é a consulta estática, uma vez que construímos, não podemos alterar a estrutura da consulta.


2
Não tão. Com o HQL, você pode definir propriedades com o identificador ':' e, em seguida, substituir essas propriedades por valores exclusivos. Por exemplo, consulta q = session.createQuery ("SELECT: aValue FROM minha_tabela"); e depois q.setParameter ("aValue", "some_column_name");
MattC

@MattC No seu exemplo, você está alterando os valores dos parâmetros, não a estrutura da consulta.
czar

4

Não quero chutar um cavalo morto aqui, mas é importante mencionar que as consultas de critérios agora estão obsoletas. Use HQL.


1

Também prefiro Consultas de critério para consultas dinâmicas. Mas eu prefiro o hql para consultas de exclusão, por exemplo, se excluir todos os registros da tabela filho para o ID pai 'xyz', é facilmente alcançado pelo HQL, mas, para os critérios da API, primeiro devemos disparar n número de consultas de exclusão onde n é o número de filhos registros de tabela.


0

A maioria das respostas aqui são enganosas e mencionam que Criteria Queriessão mais lentas que HQL, o que na verdade não é o caso.

Se você se aprofundar e executar alguns testes, verá que as Consultas de Critérios têm um desempenho muito melhor que o HQL comum .

E também com a Consulta de Critérios, você obtém o controle Orientado a Objetos, que não existe no HQL .

Para mais informações, leia esta resposta aqui .


0

Existe outro caminho. Acabei criando um analisador HQL baseado na sintaxe original do hibernate, para analisar primeiro o HQL, para injetar dinamicamente parâmetros dinâmicos ou adicionar automaticamente alguns filtros comuns para as consultas HQL. Funciona muito bem!


0

Este post é bastante antigo. A maioria das respostas fala sobre os critérios do Hibernate, não sobre os critérios da JPA. O JPA 2.1 adicionou CriteriaDelete / CriteriaUpdate e EntityGraph que controla o que exatamente buscar. A API de critérios é melhor, pois Java é OO. É por isso que o JPA é criado. Quando o JPQL é compilado, ele será traduzido para a árvore AST (modelo OO) antes de traduzido para o SQL.


-3

O HQL pode causar problemas de segurança , como injeção de SQL.


11
Esses problemas não são causados ​​pelo HQL, mas pela falta de entendimento das práticas básicas de desenvolvimento de software. Também posso criar código propenso a ataques de injeção de sql com critérios API.
Jens Schauder

1
É como dizer "consultar um RDBMS a partir de Java pode causar problemas de segurança na injeção SQL": D
Czar
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.