JPA和Hibernate - Criteria与JPQL或HQL

cre*_*zel 292 java hibernate hql criteria hibernate-criteria

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

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

cre*_*zel 211

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

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

  • 此外,尽管Criteria看起来更加类型安全,但唯一可以让您感到安全的是测试. (12认同)

Var*_*hta 92

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".

  • 只是向浏览的人指出。这个答案是 2008 年的。现在可能不再是这样了。http://dimovelev.blogspot.com/2015/02/performance-pitfalls-hibernate-criteria.html (3认同)

Cra*_*ker 41

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

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

由于HQL非常像SQL(大多数开发人员已经非常熟悉),因此这些"不必记住"的参数不会带来太大的影响.如果HQL更加不同,那么这将更加重要.

  • 这些论点不含水(就HQL而言).它不必涉及字符串连接.OO版本不容易出错,这是没有根据的.它同样容易出错但是有不同的类型.知道调用什么方法的努力与知道在HQL中调用哪些符号没有多大区别(我的意思是,严肃地说,我们不是在这里解决PDE.) (12认同)

Art*_*mas 35

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


Bri*_*ing 31

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


Ale*_*ler 22

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

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


Arv*_*ind 21

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

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

  • 几个点分页在HQL中有:你可以使用`limit offset:rows`在hql中你可以使用`setParameter避免sql注入 (11认同)

小智 13

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

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

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

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

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

  • HQL不是SQL注入安全的 (13认同)
  • 通过添加'setParameter'来实现HQL IS sql注入安全 (4认同)
  • @Zafar:您只能使用投影选择实体的某些属性 (2认同)

Tim*_*per 13

要使用两全其美,表现力和HQL的简洁和标准的动态性考虑使用Querydsl.

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

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


Mig*_*ing 11

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

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

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

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

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


Vla*_*cea 10

在运行时动态应用查询过滤器时,Criteria API更适合动态生成的查询.因此,为了在构建动态查询时防止SQL注入攻击,Criteria API是一个非常好的选择.

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

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

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

值得注意的是,如果您需要修改它们,选择具有JPQL或Criteria API的实体是有意义的.否则,DTO投影表现更好.查看此文章了解更多信息.


小智 9

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


Boj*_*aut 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();
Run Code Online (Sandbox Code Playgroud)

所以在我们的例子中,返回的记录是所需属性的映射.


Pre*_*raj 7

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

资源


use*_*378 5

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

  • 不是这样.使用HQL,您可以使用":"标识符设置属性,然后使用唯一值替换这些属性.例如,Query q = session.createQuery("SELECT:aValue FROM my_table"); 然后是q.setParameter("aValue","some_column_name"); (2认同)

Esk*_*kir 5

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