JPA和Hibernate-条件与JPQL或HQL


295

使用CriteriaHQL有何利弊?Criteria API是在Hibernate中表达查询的一种很好的面向对象的方式,但是有时候Criteria Queries比HQL更难以理解/构建。

您何时使用标准以及何时使用HQL?在哪种用例中,您更喜欢什么?还是只是口味问题?


正确的答案是“取决于用例”。
Hace

这个工具呢?它允许以对象方式构造常见查询:受保护的子句select(){return em.select(“ DISTINCT i”).from(this.getName(),“ i”).joinFetch(“ i.locale lf”) } public T findBySlug(String slug){return(T)this.select().join(“ i.locale l”); .where(“ l.slug =?”,slug).fetchSingle(); }
Vojtěch

1
定义了一个基于意见的问题,但人们并没有抓住这个机会...根据网站常见问题解答

Answers:


212

我最喜欢动态查询的条件查询。例如,动态添加一些订购或根据某些参数省去某些零件(例如限制)要容易得多。

另一方面,我将HQL用于静态和复杂查询,因为它更易于理解/阅读HQL。另外,我认为HQL功能更强大,例如对于不同的联接类型。


13
同样,尽管Criteria看起来更类型安全,但唯一能让您感到安全的是测试。

有没有很好的例子说明为什么在某些情况下HQL比标准api更好?我读了一个博客的结尾,但一无所知。如果您能提供帮助,将不胜感激。谢谢。链接-javalobby.org/articles/hibernatequery102
Erran Morad

以上所有原因-我也更喜欢Criteria而不是HQL,因为它对程序员更安全,从而减少了编码错误-未验证HQL字符串的编译。
努诺2014年

但是,存在在分页时检索不同实体的问题。这样做时,我会选择HQL以避免问题...
Anthony Webster

在列模型的元模型中使用带有条件查询的条件查询有助于在重构过程中不破坏任何内容,并且可以使用现代IDE中的简单命令重命名代码中的所有匹配项。
马西莫'18

92

HQL和criteriaQuery之间在性能方面有所不同,每次您使用criteriaQuery触发查询时,它都会为表名创建一个新别名,该别名不会反映在任何数据库的上一个查询缓存中。这导致编译生成的SQL的开销,需要更多的时间来执行。

关于获取策略[http://www.hibernate.org/315.html]

  • 条件遵循映射中的惰性设置,并确保已加载要加载的内容。这意味着一个条件查询可能会导致多个SQL立即执行SELECT语句,以使用所有非延迟映射的关联和集合来获取子图。如果要更改“方式”,甚至要更改“内容”,请使用setFetchMode()启用或禁用特定集合或关联的外部联接获取。条件查询也完全尊重提取策略(联接,选择,子选择)。
  • HQL尊重映射中的延迟设置,并确保已加载要加载的内容。这意味着一个HQL查询可能会导致多个SQL立即SELECT语句来获取具有所有非延迟映射的关联和集合的子图。如果要更改“方式”,甚至要更改“内容”,请使用LEFT JOIN FETCH启用特定集合的外部联接获取或可空的多对一或一对一关联,或使用JOIN FETCH启用内部联接获取非空多对一或一对一关联。HQL查询不遵守映射文档中定义的任何fetch =“ join”。

1
只是指出任何正在浏览的人。该答案来自2008年。情况可能不再如此。dimovelev.blogspot.com/2015/02/…–
Amalgovinus

41

Criteria是一种面向对象的API,而HQL则是字符串连接。这意味着适用面向对象的所有好处:

  1. 在所有其他条件相同的情况下,OO版本不太容易出错。任何旧字符串都可以追加到HQL查询中,而只有有效的Criteria对象才能将其放入Criteria树中。实际上,条件类受到更多的限制。
  2. 使用自动完成功能,OO更容易发现(因此,至少对于我来说更易于使用)。您不一定需要记住查询的哪一部分去了哪里。IDE可以帮助您
  3. 您也不需要记住语法的细节(例如哪些符号在哪里)。您只需要知道如何调用方法和创建对象。

由于HQL非常像SQL(大多数开发人员已经很了解),所以这些“不必记住”的参数就没有那么重要了。如果HQL更加不同,那么这将更加重要。


12
这些论点不成立(相对于HQL)。它不必涉及字符串连接。OO版本不太容易出错的说法没有根据。它同样容易出错,但种类不同。知道调用什么方法的工作与知道在HQL中调用什么符号的工作没有太大区别(我是说,认真的说,我们不是在这里解决PDE。)
luis.espinal 2010年

有没有很好的例子说明为什么在某些情况下HQL比标准api更好?我读了一个博客的结尾,但一无所知。如果您能提供帮助,将不胜感激。谢谢。链接-javalobby.org/articles/hibernatequery102
Erran Morad

1
HQL命名查询是在部署时编译的,这时将检测到缺少的字段(可能是错误的重构?)。我认为这使代码比标准更具弹性,并且实际上不易出错。
narduk

Criteria中的自动完成几乎没有用,因为属性只是字符串。
路易斯·马丁内斯

35

当我不知道在哪些数据上使用什么输入时,我通常使用Criteria。就像在搜索表单上,用户可以输入1到50个项目中的任何一个,我不知道他们将搜索什么。在检查用户要搜索的内容时,将更多内容附加到条件上非常容易。我认为在这种情况下进行HQL查询会有些麻烦。当我完全知道自己想要什么时,HQL很棒。


1
这是一个很好的评论。当前,我们为搜索表单构建非常大的HQL字符串,该表单包含通过联接的许多不同对象。看起来很丑。查看条件是否可以清除该条件。有趣的...
cbmeeks 2012年

谢谢。这是一个很好的例子。你能再给我一点吗?
Erran Morad 2014年

31

HQL更容易阅读,更容易使用Eclipse Hibernate插件之类的工具进行调试,并且更易于记录。条件查询更适合于在运行时确定许多行为的情况下构建动态查询。如果您不了解SQL,那么我可以使用Criteria查询来理解,但是总体而言,如果我知道自己想要什么,我更喜欢HQL。



21

Criteria Api是Hibernate的良好概念之一。根据我的观点,这些是我们可以区分HQLCriteria Api的几点

  1. HQL将对数据执行选择和非选择操作,但是Criteria仅用于选择数据,我们不能使用条件执行非选择操作。
  2. HQL适合执行静态查询,而条件适合执行动态查询
  3. HQL不支持分页概念,但是我们可以使用Criteria实现分页。
  4. 与HQL相比,执行标准所花的时间更多。
  5. 使用Criteria,我们可以安全地使用SQL Injection,因为它可以动态生成查询,但是在HQL中,由于查询是固定的或参数化的,因此SQL Injection是不安全的

11
HQL中有几个分页:您可以使用limit offset:rows 在hql中,可以避免使用sql注入setParameter
Viswanath Lekshmanan

13

为了充分利用这两个方面的优势,HQL的表达性和简洁性以及Criteria的动态性质考虑使用Querydsl

Querydsl支持JPA /休眠,JDO,SQL和集合。

我是Querydsl的维护者,所以这个答案是有偏见的。


13

对我而言,条件很容易理解和进行动态查询。但是到目前为止,我说的缺点是它加载了所有多对一关系,因为我们只有三种类型的FetchModes,即选择,代理和默认,并且在所有这些情况下,它都加载了多对一(如果这样的话,我是错的我出来:))

Criteria的第二个问题是它加载了完整的对象,即,如果我只想加载一个雇员的EmpName,它不会提出这个insted,它会提出完整的Employee对象,由于这个问题,我确实可以从中获取EmpName,它确实在报告。就像HQL只是加载(不加载关联/关系)那样,您想要什么,因此可以多次提高性能。

Criteria的一项功能是,由于它具有动态查询生成功能,因此它可以保护您免受SQL Injection的攻击,因为在HQL中,由于ur的查询是固定的或参数化的,因此对于SQL Injection是不安全的。

另外,如果您在ur aspx.cs文件中编写HQL,那么您与UR DAL紧密相关。

总的来说,我的结论是,有些地方像报告一样无法没有HQL,因此可以使用它们,否则Criteria更加易于管理。


13
HQL是不是SQL注入安全
Varun的梅塔

我认为Criteria不是注射安全的。请参阅我的文章在这里:stackoverflow.com/questions/6746486/...
Smith先生

4
HQL通过添加'的setParameter' SQL注入安全
Javatar

2
@Zafar:您可以使用投影选择一个实体的某些性质
的Răzvan弗拉菲乌斯熊猫

@Zafar可以在条件查询中设置投影以选择特定的列。您可以获取EmpName,而无需获取完整的对象。
哈特里

12

标准API

Criteria API更适合动态生成的查询。因此,如果您想添加WHERE子句过滤器,JOIN子句或更改ORDER BY子句或投影列,那么Criteria API可以帮助您动态生成查询,同时还可以防止SQL注入攻击

另一方面,条件查询的表现力较差,甚至可能导致非常复杂且效率低下的SQL查询,如本文所述

JPQL和HQL

JPQL是JPA标准实体查询语言,而HQL扩展了JPQL并添加了一些特定于Hibernate的功能。

JPQL和HQL表现力很强,类似于SQL。与Criteria API不同,JPQL和HQL使得预测JPA提供程序生成的基础SQL查询变得容易。与标准查询相比,审查一个人的HQL查询也要容易得多。

值得注意的是,如果需要修改使用JPQL或Criteria API的实体,则是有意义的。否则,DTO投影是更好的选择。

结论

如果不需要更改实体查询结构,请使用JPQL或HQL。如果您需要更改过滤或排序标准或更改投影,请使用Criteria API。

但是,仅仅因为您使用的是JPA或Hibernate,并不意味着您不应该使用本机SQL。SQL查询非常有用,并且JPQL和Criteria API不能替代SQL。请查看本文以获取有关此主题的更多详细信息。



11

对我而言,在Criteria上最大的赢家是Example API,您可以在其中传递对象,然后休眠将基于这些对象属性构建查询。

除此之外,标准API也有其独特之处(我相信休眠团队正在重新设计api),例如:

  • 条件.createAlias(“ obj”)强制使用内部联接,而不是可能的外部联接
  • 您不能两次创建相同的别名
  • 一些sql子句没有简单的标准对应项(例如subselect)
  • 等等

当我想要类似于sql的查询(从“状态='已阻止”的用户中删除)查询时,我倾向于使用HQL,而当我不想使用字符串附加时,我倾向于使用条件。

HQL的另一个优点是,您可以事先定义所有查询,甚至可以将它们外部化为一个文件左右。


9

Criteria API提供了SQL或HQL均未提供的一项独特功能。即。它允许对查询进行编译时检查。


7

在一开始,我们主要在应用程序中使用Criteria,但由于性能问题,后来将其替换为HQL。
主要是我们使用带有多个联接的非常复杂的查询,这导致在Criteria中产生多个查询,但在HQL中进行了非常优化。
情况是,我们仅对特定对象而不是完整对象使用几种属性。对于Criteria,问题还在于字符串连接。
假设要在HQL中显示用户的姓名和姓氏,这很容易,(name || ' ' || surname)但是在Crteria中则不可能。
为了克服这个问题,我们使用了ResultTransormers,其中有些方法对所需的结果实施了这种串联。
今天,我们主要使用HQL,如下所示:

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

因此,在本例中,返回的记录是所需属性的映射。


1
通过Criteria,您可以使用org.hibernate.criterion.CriteriaSpecification.ALIAS_TO_ENTITY_MAP
AA。

根据我的经验返回地图列表的效果非常差。我更喜欢返回一个对象数组列表或一个bean列表(您始终可以定义一个适合您特定结果集的bean)。
Lluis Martinez

7
  • HQL用于对数据执行选择和非选择操作,但是Criteria仅用于选择数据,我们不能使用条件执行非选择操作
  • HQL适合执行静态查询,而条件适合执行动态查询
  • HQL不支持分页概念,但是我们可以使用Criteria实现分页
  • 与HQL相比,以前需要花费更多时间来执行的条件
  • 使用Criteria,我们可以安全使用SQL Injection,因为它可以动态生成查询,但是在HQL中,由于您的查询是固定的或参数化的,因此SQL Injection是不安全的。

资源


为了澄清起见,可以使用Hibernate的Criteria API进行条件查询,但是JPA条件查询涵盖选择,更新和删除。请参阅CriteriaUpdate<T>CriteriaDelete<T>供参考。
罗斯(Naros)2016年

5

对于动态的条件查询,我们可以根据输入来构造查询。如果Hql查询是静态查询,则一旦构造,就无法更改查询的结构。


2
不是这样 使用HQL,您可以使用':'标识符设置属性,然后将这些属性替换为唯一值。例如,查询q = session.createQuery(“ SELECT:aValue FROM my_table”); 然后q.setParameter(“ aValue”,“ some_column_name”);
MattC

@MattC在您的示例中,您要更改参数的值,而不是查询的结构。
沙皇2015年

4

我不想在这里踢死人,但重要的是要提到现在不建议使用Criteria查询。使用HQL。


1

对于动态查询,我也更喜欢使用条件查询。但是我更喜欢使用hql进行删除查询,例如,如果从子表中删除父ID为'xyz'的所有记录,HQL可以轻松实现,但是对于标准API,我们首先必须触发n个删除查询,其中n是子查询数表记录。


0

此处的大多数答案都具有误导性,并提到Criteria Queries比慢HQL,但实际上并非如此。

如果您深入研究并执行一些测试,您将看到“ 条件查询”的性能要比常规HQL好得多

而且通过Criteria Query,您可以获得HQL所不具备的面向对象的控件

有关更多信息,请在此处阅读此答案。


0

还有另一种方式。我最后基于休眠原始语法创建了一个HQL解析器,因此它首先解析HQL,然后它可以动态地注入动态参数或自动为HQL查询添加一些常见的过滤器。效果很好!


0

这篇文章很老了。大多数答案都谈论Hibernate标准,而不是JPA标准。JPA 2.1添加了CriteriaDelete / CriteriaUpdate和EntityGraph,它们控制要精确获取的内容。由于Java是OO,因此Criteria API更好。这就是创建JPA的原因。编译JPQL时,它将先转换为AST树(OO模型),然后再转换为SQL。


-3

HQL可能导致安全问题,例如SQL注入。


11
这些问题不是由HQL引起的,而是由对基本软件开发实践的缺乏了解引起的。我也可以使用条件api创建易于进行sql注入攻击的代码。
延斯·肖特

1
这就像说“从Java查询RDBMS可能引起SQL注入安全性问题”:D
Czar
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.