JPA和Hibernate – Criteria与JPQL或HQL

使用Criteria或HQL有什么优点和缺点? Criteria API是在Hibernate中expression查询的一种很好的面向对象的方式,但是有时候Criteria Queries比HQL更难理解/构build。

你什么时候使用Criteria和HQL? 你喜欢哪种用例? 还是仅仅是品味的问题?

我大多更喜欢dynamic查询的条件查询。 例如,dynamic地添加一些sorting或者根据某些参数留下一些部分(例如限制)会容易得多。

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

HQL和criteriaQuery之间在性能上存在差异,每次使用criteriaQuery启动查询时,都会为表名称创build一个新的别名,而不会在任何数据库的最后查询caching中反映出来。 这导致编译生成的SQL的开销,需要更多的时间来执行。

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

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

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

  1. 所有其他的都相同,OO版本不太容易出错。 任何旧的string都可以附加到HQL查询中,而只有有效的Criteria对象可以将其添加到Criteria树中。 有效地,标准类更加受限制。
  2. 使用自动完成function时,面向对象更容易被发现(因此至less对我来说更容易使用)。 您不一定需要记住查询的哪些部分在哪里; IDE可以帮助你
  3. 你也不需要记住语法的细节(比如哪个符号在哪里)。 所有你需要知道的是如何调用方法和创build对象。

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

HQL更容易阅读,更容易使用Eclipse Hibernate插件等工具进行debugging,并且更易于logging。 条件查询更适合构builddynamic查询,这些dynamic查询在运行时确定了很多行为。 如果你不知道SQL,我可以理解使用Criteria查询,但总体而言,如果我知道我想要的是什么,我更喜欢HQL。

当我不知道在哪些数据块上使用什么input时,我通常会使用Criteria。 就像在search表单上,用户可以input1到50个项目中的任何一个,我不知道他们将要search什么。 当我检查用户正在search的内容时,添加更多的标准非常简单。 我认为在这种情况下放置一个HQL查询会有点麻烦。 虽然当我确切地知道我想要什么时,HQL是伟大的。

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

你可以在这里find更多的信息:

Criteria Api是Hibernate的一个很好的概念。 根据我的观点,这些是我们可以在HQLCriteria Api之间做出区别的几点

  1. HQL是对数据执行select和非select操作,但是Criteria只是用于select数据,我们不能使用条件执行非select操作。
  2. HQL适合执行静态查询,其中Criteria适合执行dynamic查询
  3. HQL不支持分页概念,但是我们可以通过Criteria实现分页。
  4. 过去比HQL需要更多的时间来执行的标准。
  5. 使用Criteria,我们使用SQL注入是安全的,因为它的dynamic查询生成,但在HQL中,因为您的查询是固定的或参数化的,SQL注入

对我来说Criteria是一个相当容易理解和制作dynamic查询。 但是我迄今为止所说的缺陷是,它加载了所有的多对一的关系,因为我们只有三种types的FetchMode,即Select,Proxy和Default,并且在所有这些情况下它加载了许多(如果这样的话可能是我错了我出:))

Criteria的第二个问题是,它加载完整的对象,即如果我想只是加载员工EmpName它不会拿出这个insted它拿出完整的员工对象,我可以从它得到EmpName,因为它真的工作不好报告 。 作为HQL只是加载(没有加载关联/关系)你想要什么,所以提高性能多次。

Criteria的一个特点是它可以安全地从SQL注入,因为它的dynamic查询生成在HQL中,因为ur查询是固定的或参数化的,所以对于SQL注入来说是不安全的。

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

总的来说,我的结论是,有些地方你不能没有HQL报告,所以使用其他标准更容易pipe理。

为了充分利用这两个世界,HQL的expression性和简洁性以及Criteria的dynamic性考虑使用Querydsl 。

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

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

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

除此之外,标准API有其怪癖(我相信Hibernate团队正在重新制定api),例如:

  • 一个criteria.createAlias(“obj”)强制内部连接,而不是可能的外部连接
  • 你不能两次创build相同的别名
  • 一些sql子句没有简单的标准对应(比如子查询)
  • 等等

我倾向于使用HQL,当我想要类似于SQL查询(从用户where status ='blocked'删除),我倾向于使用条件,当我不想使用string附加。

HQL的另一个好处是你可以事先定义你所有的查询,甚至把它们外部化为一个文件。

Criteria API提供了一个独特的function,SQL或HQL都不提供。 即。 它允许编译时间检查查询。

当查询filter在运行时dynamic应用时,Criteria API更适合于dynamic生成的查询。 因此,在构builddynamic查询时要防止SQL注入攻击 ,Criteria API是一个非常好的select。

标准查询不那么富有performance力,而且可以很容易地用一个非常复杂和低效的SQL生成的查询来结束 。 我曾经join了一个大型企业应用程序,其中Criteria API是默认的查询方法,甚至没有广泛的代码审查可以克服不知道我们将要结束的SQL查询的恐惧。

JPQL或HQL更富有performance力,预测关联生成的SQL查询更容易。 审查一个人的HQL查询比标准要容易得多。

大多数实体查询用例不需要dynamicwhere子句,因此您可以使用JPQL实现大多数查询,同时将标准留给dynamic子查询。

值得注意的是,如果您需要修改它们,那么使用JPQL或Criteria APIselect实体是有意义的。 否则,DTO投影效果会更好。 看看这篇文章的更多信息 。

我们在开始的时候主要使用了Criteria,但是之后由于性能问题而被HQL取代。
主要是我们使用非常复杂的查询与几个连接,导致在Criteria多个查询,但在HQL非常优化。
这种情况是我们在特定的对象上使用了几个propeties而不是完整的对象。 与标准问题也是string连接。
比方说,如果你需要在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(); 

所以在我们的情况下,返回的logging是所需属性的地图。

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

资源

条件dynamic查询我们可以根据我们的input构build查询。如果Hql查询是我们构造的静态查询,我们不能改变查询的结构。

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

我还喜欢dynamic查询的条件查询。 但我更喜欢hql删除查询,例如,如果从父表id删除所有logging的父母id'xyz',这很容易通过HQL来实现,但是对于标准API首先我们必须触发n个删除查询,其中n是孩子的数量表格logging。

这里的答案大多是误导性的,并提到Criteria QueriesHQL慢,实际上并非如此。

如果深入研究并执行一些testing,您将看到标准查询比常规HQL执行得更好

而且在Criteria Query中,你也得到了面向对象的控制 ,而这与HQL不存在。

欲了解更多信息,请阅读这个答案。

HQL会导致SQL注入等安全问题。