JPA和Hibernate -标准vs. JPQL或HQL

使用标准HQL的优点和缺点是什么?Criteria API是一种在Hibernate中表达查询的面向对象的好方法,但有时Criteria queries比HQL更难理解/构建。

什么时候使用标准,什么时候使用HQL?在哪些用例中您更喜欢什么?还是说这只是个人口味的问题?

156549 次浏览

对于动态查询,我更喜欢使用条件查询。例如,根据某些参数,动态地添加一些排序或保留一些部分(例如限制)要容易得多。

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

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

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

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

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

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

对我来说,Criteria最大的优势是示例API,在这里你可以传递一个对象,hibernate将基于这些对象属性构建一个查询。

除此之外,标准API也有它的怪癖(我相信hibernate团队正在重做API),比如:

  • a criteria.createAlias("obj")强制使用内部连接而不是可能的外部连接
  • 您不能两次创建相同的别名
  • 有些SQL子句没有简单的对应条件(比如子选择)
  • 等。

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

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

HQL和criteriaQuery在性能上是有区别的,每次你使用criteriaQuery发起查询时,它会为表名创建一个新的别名,这个别名不会反映在任何DB的最后一个查询缓存中。这会导致编译生成的SQL的开销,需要更多的时间来执行。

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

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

对我来说,Criteria是一个很容易理解的动态查询。但我说到目前为止的缺陷是,它加载所有的多-一等关系,因为我们只有三种类型的FetchModes,即选择,代理和默认,在所有这些情况下,它加载多-一(可能是我错了,如果这样帮助我:))

第二个问题与标准是,它加载完整的对象,即,如果我想只是加载员工的EmpName,它不会提出这个,而是提出完整的员工对象,我可以从它得到EmpName,由于这个这在报道中真的很糟糕。因为HQL只是加载(没有加载关联/关系)你想要的,所以性能会提高很多倍。

Criteria的一个特点是,它将使你免受SQL注入的伤害,因为它的动态查询生成,而在HQL中,ur的查询要么是固定的,要么是参数化的,因此在SQL注入中不安全。

同样,如果你在你的aspx.cs文件中编写HQL,那么你与你的DAL紧密耦合。

总的来说,我的结论是,有些地方你不能没有HQL,比如报告,所以使用它们,否则Criteria更容易管理。

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

你可以在这里找到更多信息:

为了两全其美,HQL的表达性和简洁性以及Criteria的动态特性可以考虑使用Querydsl

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

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

在我们的应用程序中,我们一开始主要使用Criteria,但后来由于性能问题被HQL取代。
我们主要使用非常复杂的查询和几个连接,这导致Criteria中的多个查询,但在HQL中进行了非常优化。
这种情况是,我们只在特定对象上使用几个属性,而不是在完整的对象上使用。对于Criteria,问题也是字符串连接。
比方说,如果你需要在HQL中显示用户的姓名和姓氏,这很容易(name || ' ' || surname),但在criteria中这是不可能的。
为了克服这个问题,我们使用了resulttransformer,其中有实现所需结果的方法。
今天我们主要像这样使用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();

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

Criteria api提供了一个SQL和HQL都不提供的独特特性。ie。它允许对查询进行编译时检查。

对于动态条件查询,我们可以根据我们的输入构造查询..在Hql查询是静态查询的情况下,一旦我们构造,我们就不能改变查询的结构。

HQL会引起诸如SQL注入之类的安全问题。

Criteria Api是Hibernate的一个很好的概念。根据我的观点,这些是我们可以区分HQL标准Api的少数点

  1. HQL对数据执行选择和非选择操作,但Criteria仅用于选择数据,我们不能使用Criteria执行非选择操作。
  2. HQL适用于执行静态查询,as Criteria适用于执行动态查询
  3. HQL不支持分页概念,但我们可以用Criteria实现分页。
  4. 标准执行的时间通常比HQL多。
  5. 在Criteria中,我们使用SQL注入是安全的,因为它是动态查询生成的,但在HQL中,由于您的查询要么是固定的,要么是参数化的,因此SQL注入是不安全的

对于动态查询,我也更喜欢使用条件查询。但我更喜欢hql删除查询,例如,如果从父id 'xyz'的子表中删除所有记录,这很容易由hql实现,但对于标准API,首先我们必须触发n个删除查询,其中n是子表记录的数量。

标准API

Criteria API更适合动态生成查询。因此,如果您想添加WHERE子句过滤器、JOIN子句,或者改变ORDER BY子句或投影列,Criteria API可以帮助您以一种防止SQL注入攻击的方式动态生成查询。

另一方面,Criteria查询表达能力较差,甚至可能导致非常复杂和低效的SQL查询。

JPQL和HQL

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

JPQL和HQL非常具有表现力,并且类似于SQL。与Criteria API不同,JPQL和HQL可以很容易地预测JPA提供者生成的底层SQL查询。复查HQL查询也比Criteria查询容易得多。

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

结论

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

然而,仅仅因为您正在使用JPA或Hibernate,这并不意味着您不应该使用本机SQL。SQL查询非常有用,JPQL和Criteria API不是SQL的替代品。

  • HQL对数据执行选择和非选择操作,但Criteria仅用于选择数据,我们不能使用Criteria执行非选择操作
  • HQL适用于执行静态查询,as Criteria适用于执行动态查询
  • HQL不支持分页概念,但是我们可以用Criteria实现分页
  • 过去执行标准比执行HQL花费更多的时间
  • 使用Criteria,我们使用SQL注入是安全的,因为它是动态查询生成的,但在HQL中,由于您的查询要么是固定的,要么是参数化的,因此SQL注入是不安全的。

source

这里的大多数答案都是误导性的,并提到Criteria QueriesHQL慢,但事实并非如此。

如果你深入研究并执行一些测试,你会看到Criteria查询的性能比常规HQL要好得多

同样,使用标准查询,你会得到面向对象控制,这是HQL所没有的。

要了解更多信息,请阅读这个答案在这里

我不想在这里白费口舌,但有一点很重要,那就是Criteria查询现在已被弃用。使用HQL。

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

这个帖子很老了。大多数答案谈论的是Hibernate标准,而不是JPA标准。JPA 2.1增加了CriteriaDelete/CriteriaUpdate和EntityGraph来控制获取什么。Criteria API更好,因为Java是面向对象的。这就是创建JPA的原因。当JPQL被编译时,它将被转换为AST树(OO模型),然后再转换为SQL。

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

它更适合使用它来构建库,而不是使用jpql或hql。

例如,我已经使用Criteria API构建了spring-data-jpa-mongodb-expressions(与spring数据QBE相同)。

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