JPA和Hibernate - Criteria与JPQL或HQL

时间:2008-10-13 12:47:33

标签: java hibernate hql criteria hibernate-criteria

使用CriteriaHQL有哪些优缺点? Criteria API是一种很好的面向对象的方式来表达Hibernate中的查询,但有时Criteria Queries比HQL更难理解/构建。

何时使用Criteria和何时使用HQL?您更喜欢哪种用例?或者仅仅是品味问题?

22 个答案:

答案 0 :(得分:205)

我更喜欢Criteria Queries进行动态查询。例如,根据某些参数,动态添加一些排序或保留一些部分(例如限制)要容易得多。

另一方面,我正在使用HQL进行静态和复杂查询,因为它更容易理解/读取HQL。另外,我认为HQL更强大,例如对于不同的连接类型。

答案 1 :(得分:90)

HQL和criteriaQuery之间的性能存在差异,每次使用criteriaQuery触发查询时,它都会为表名创建一个新别名,该别名不反映在任何数据库的最后查询缓存中。这导致编译生成的SQL的开销,花费更多的时间来执行。

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

  
      
  • Criteria尊重映射中的延迟设置,并保证加载您想要加载的内容。这意味着一个Criteria查询可能会导致多个SQL立即SELECT语句来获取具有所有非延迟映射关联和集合的子图。如果要更改“how”甚至“what”,请使用setFetchMode()为特定集合或关联启用或禁用外部联接提取。 Criteria查询还完全尊重提取策略(join vs select vs subselect)。
  •   
  • HQL尊重映射中的延迟设置,并保证加载要加载的内容。这意味着一个HQL查询可能会导致多个SQL立即SELECT语句获取具有所有非延迟映射关联和集合的子图。如果要更改“how”甚至“what”,请使用LEFT JOIN FETCH为特定集合启用外部联接提取,或者为可以多对一或一对一关联的可空连接,或使用JOIN FETCH启用内部联接获取非可空的多对一或一对一关联。 HQL查询不遵守映射文档中定义的任何fetch =“join”。
  •   

答案 2 :(得分:38)

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

  1. 在其他条件相同的情况下,OO版本不太容易出错。任何旧字符串都可以附加到HQL查询中,而只有有效的Criteria对象才能将其添加到Criteria树中。实际上,Criteria类更受限制。
  2. 通过自动完成,OO更容易被发现(因此至少对我来说更容易使用)。您不一定需要记住查询的哪些部分在哪里; IDE可以帮助你
  3. 您也不需要记住语法的细节(比如哪些符号去哪里)。您需要知道的是如何调用方法和创建对象。
  4. 由于HQL非常像SQL(大多数开发人员已经非常熟悉),因此这些“不必记住”的参数不会带来太大的影响。如果HQL更加不同,那么这将更加重要。

答案 3 :(得分:34)

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

答案 4 :(得分:31)

HQL更容易阅读,使用Eclipse Hibernate插件等工具更容易调试,更容易记录。 Criteria查询更适合构建动态查询,其中许多行为是在运行时确定的。如果您不了解SQL,我可以理解使用Criteria查询,但总体而言,如果我知道我想要的是什么,我更喜欢HQL。

答案 5 :(得分:22)

条件是指定利用二级查询缓存中的特殊优化的自然键查找的唯一方法。 HQL没有任何方法来指定必要的提示。

您可以在此处找到更多信息:

答案 6 :(得分:20)

Criteria Api是Hibernate的一个很好的概念。根据我的观点,这些是我们能够在 HQL Criteria Api

之间做出改变的几点。
  1. HQL是对数据执行选择和非选择操作,但Criteria仅用于选择数据,我们无法使用条件执行非选择操作。
  2. HQL适用于执行静态查询,其中Criteria适合执行动态查询
  3. HQL不支持分页概念,但我们可以通过Criteria实现分页。
  4. 标准过去比HQL花费更多时间执行。
  5. 使用Criteria,我们可以安全地使用 SQL注入,因为它的动态查询生成,但是在HQL中,因为您的查询是固定的或参数化的,所以SQL注入没有安全性

答案 7 :(得分:13)

对我而言,Criteria非常容易理解和制作动态查询。但我到目前为止所说的缺陷是它加载了所有多个等关系,因为我们只有三种类型的FetchModes,即Select,Proxy和Default,在所有这些情况下它加载了多个(如果有帮助,可能是我错了)我出去:))

Criteria的第二个问题是它加载了完整的对象,即如果我只想加载一个员工的EmpName,它就不会想到它提出了完整的Employee对象,我可以从中得到EmpName,因为这个报告确实很糟糕。 HQL只是加载(不加载关联/关系)你想要的,所以多次提高性能。

Criteria的一个特性是它可以安全地使用SQL注入因为它的动态查询生成,因为在HQL中你的查询是固定的或参数化的,所以从SQL注入是不安全的。

另外,如果你在ur aspx.cs文件中编写HQL,那么你就会与你的DAL紧密结合。

总的来说,我的结论是,如果没有像报告这样的HQL,你就无法生存。所以使用其他标准更容易管理。

答案 8 :(得分:12)

为了充分利用这两个方面,HQL的表现力和简洁性以及标准的动态性质考虑使用Querydsl

Querydsl支持JPA / Hibernate,JDO,SQL和Collections。

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

答案 9 :(得分:11)

对我来说,Criteria上最大的胜利是Example API,你可以在其中传递一个对象,而hibernate将根据这些对象属性构建一个查询。

除此之外,标准API有其怪癖(我相信hibernate团队正在重新设计api),如:

  • 一个criteria.createAlias(“obj”)强制内部联接而不是可能的外部联接
  • 您不能两次创建相同的别名
  • 某些sql子句没有简单的标准对应物(如子选择)

当我想要类似于sql的查询(从status ='blocked'的用户中删除)时,我倾向于使用HQL,并且当我不想使用字符串追加时,我倾向于使用条件。

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

答案 10 :(得分:9)

Criteria api提供了SQL或HQL都没有提供的一个独特功能。即。它允许编译时检查查询。

答案 11 :(得分:9)

在运行时动态应用查询过滤器时,Criteria API更适合动态生成的查询。因此,在构建动态查询时,要prevent SQL Injection attacks,Criteria API是一个非常好的选择。

标准查询的表达力较低,您可以轻松地使用非常复杂且效率低下的SQL generated query。我曾经加入了一个大型企业应用程序,其中Criteria API是默认的查询方法,甚至没有广泛的代码审查可以克服不知道我们最终会得到什么SQL查询的恐怖。

JPQL或HQL更具表现力,预测相关生成的SQL查询要容易得多。查看一个HQL查询比使用标准查询要容易得多。

大多数实体查询用例都不需要动态where子句,因此您可以使用JPQL实现大多数查询,同时保留动态的条件。

值得注意的是,如果您需要修改具有JPQL或Criteria API的实体,则有意义。否则,DTO投影表现更好。查看this article for more info

答案 12 :(得分: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();

所以在我们的例子中,返回的记录是所需属性的地图。

答案 13 :(得分:7)

  • HQL是对数据执行选择和非选择操作,但Criteria仅用于选择数据,我们无法使用条件执行非选择操作
  • HQL适用于执行静态查询,其中Criteria适合执行动态查询
  • HQL不支持分页概念,但我们可以使用Criteria
  • 实现分页
  • 标准过去需要花费更多时间来执行HQL
  • 使用Criteria,我们使用SQL注入是安全的,因为它的动态查询生成,但在HQL中,因为您的查询是固定的或参数化的,所以SQL注入没有安全性。

source

答案 14 :(得分:5)

标准查询动态我们可以根据我们的输入构造查询。如果Hql查询是静态查询,一旦我们构造,我们就无法改变查询的结构。

答案 15 :(得分:4)

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

答案 16 :(得分:1)

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

答案 17 :(得分:0)

此处的大多数答案都具有误导性,并提到Criteria QueriesHQL慢,实际情况并非如此。

如果您深入研究并执行某些测试,您会看到 条件查询的执行情况比常规HQL 好得多。

还有标准查询,您将获得面向对象的控件 HQL 不存在。

有关详细信息,请阅读此回答here

答案 18 :(得分:0)

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

答案 19 :(得分:0)

这篇文章很老了。大多数答案都是关于Hibernate标准,而不是JPA标准。 JPA 2.1添加了CriteriaDelete / CriteriaUpdate,以及控制究竟要获取内容的EntityGraph。 Criteria API更好,因为Java是OO。这就是创建JPA的原因。编译JPQL时,它会在转换为SQL之前转换为AST树(OO模型)。

答案 20 :(得分:0)

另一点是,我认为 Criteria 更适合构建在它之上,而不是直接在最终代码中使用。

使用它比使用 jpql 或 hql 更适合构建库。

例如,我使用 Criteria API 构建了 spring-data-jpa-mongodb-expressions(与 Spring Data QBE 的做法相同)。

<块引用>

我认为 spring 数据查询生成使用的是 jpaql 而不是我不明白为什么的标准。

答案 21 :(得分:-3)

HQL可能导致SQL注入等安全性问题。