【问题标题】:JPA and Hibernate - Criteria vs. JPQL or HQLJPA 和 Hibernate - 标准与 JPQL 或 HQL
【发布时间】:2010-09-16 21:12:05
【问题描述】:

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

您何时使用 Criteria 以及何时使用 HQL?在哪些用例中你更喜欢什么?还是只是口味问题?

【问题讨论】:

  • 正确的答案是“取决于用例”。
  • 基于意见的问题的定义,但人们还没有借此机会关闭它......根据网站常见问题解答

标签: java hibernate hql criteria hibernate-criteria


【解决方案1】:

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

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

【讨论】:

  • 此外,尽管 Criteria 看起来更安全一些,但唯一能让您感到安全的就是测试。
  • 有没有什么好的例子可以说明为什么在某些情况下 HQL 比标准 api 更好?我读了一篇博客的结尾,但什么也不懂。如果您能提供帮助,将不胜感激。谢谢。链接 - javalobby.org/articles/hibernatequery102
  • 以上所有原因 - 我也更喜欢 Criteria 而不是 HQL,因为它对程序员更安全,减少编码错误 - HQL 字符串上的编译未经过验证。
  • 但是,在分页时存在检索不同实体的问题。这样做时,我会选择 HQL 以避免出现问题...
  • 使用标准查询和列名的元模型有助于在重构过程中不破坏任何内容,并使用现代 IDE 中的简单命令重命名代码中的所有事件。
【解决方案2】:

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

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

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

【讨论】:

【解决方案3】:

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

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

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

【讨论】:

  • 这些论点不成立(相对于 HQL)。它不必涉及字符串连接。 OO 版本不太容易出错是未经证实的。它同样容易出错,但类型不同。知道调用什么方法的工作与知道在 HQL 中调用什么符号没有太大区别(我的意思是,说真的,我们不是在这里解决偏微分方程。)
  • 有没有什么好的例子可以说明为什么在某些情况下 HQL 比标准 api 更好?我读了一篇博客的结尾,但什么也不懂。如果您能提供帮助,将不胜感激。谢谢。链接 - javalobby.org/articles/hibernatequery102
  • HQL 命名查询是在部署时编译的,此时会检测到缺失的字段(可能是因为重构不当?)。我认为这使代码更有弹性,实际上比标准更不容易出错。
  • Criteria 中的自动完成几乎没用,因为属性只是字符串。
【解决方案4】:

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

【讨论】:

  • 这是一个很好的评论。我们目前为包含许多不同对象的搜索表单构建了非常大的 HQL 字符串。看起来很丑。去看看一个标准是否可以清理它。有趣...
  • 谢谢。这是一个很好的例子。你能再给我一些吗?
  • 最佳解释@Arthur Thomas
【解决方案5】:

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

【讨论】:

    【解决方案6】:

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

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

    【讨论】:

      【解决方案7】:

      Criteria Api 是 Hibernate 的优秀概念之一。根据我的观点,这些是我们可以在 HQLCriteria Api

      之间做出区别的几点
      1. HQL 是对数据进行选择和非选择操作,但 Criteria 仅用于选择数据,不能使用条件进行非选择操作。
      2. HQL 适用于执行静态查询,而 Criteria 适用于执行动态查询
      3. HQL 不支持 pagination 概念,但我们可以使用 Criteria 实现分页。
      4. 执行条件过去比 HQL 需要更多时间。
      5. 使用 Criteria,我们可以安全地使用 SQL 注入,因为它会生成动态查询,但在 HQL 中,由于您的查询是固定的或参数化的,因此无法避免 SQL 注入

      【讨论】:

      • HQL 中有几个点分页:你可以使用limit offset:rows 在 hql 中你可以使用setParameter 避免sql注入
      【解决方案8】:

      标准 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 查询也比 Criteria 查询容易得多。

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

      结论

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

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

      【解决方案9】:

      要充分利用 HQL 的表达力和简洁性以及 Criteria 的动态特性,请考虑使用 Querydsl

      Querydsl 支持 JPA/Hibernate、JDO、SQL 和集合。

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

      【讨论】:

        【解决方案10】:

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

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

        Criteria 的一个特点是它可以保护你免受 SQL 注入的影响,因为它会生成动态查询,而在 HQL 中,你的查询要么是固定的,要么是参数化的,因此对 SQL 注入不安全。

        此外,如果您在您的 aspx.cs 文件中编写 HQL,那么您将与您的 DAL 紧密耦合。

        总体而言,我的结论是,有些地方如果没有 HQL 之类的报告就无法生存,因此请使用它们,否则标准更易于管理。

        【讨论】:

        • HQL 不是 SQL 注入安全的
        • 我认为 Criteria 不是注射安全的。在这里查看我的帖子:stackoverflow.com/questions/6746486/…
        • HQL 通过添加 'setParameter' 实现 sql 注入安全
        • @Zafar:您只能使用投影选择实体的某些属性
        • @Zafar 您可以在条件查询中设置投影以选择特定列。您可以获取 EmpName,无需获取完整的对象。
        【解决方案11】:

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

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

        • criteria.createAlias("obj") 强制内部联接而不是可能的外部联接
        • 您不能两次创建同一个别名
        • 一些 sql 子句没有简单的条件对应项(如子选择)

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

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

        【讨论】:

          【解决方案12】:

          Criteria api 提供了 SQL 或 HQL 都没有提供的一项独特功能。 IE。它允许对查询进行编译时检查。

          【讨论】:

            【解决方案13】:

            一开始我们在应用程序中主要使用 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();
            

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

            【讨论】:

            • 有了 Criteria 你可以使用 org.hibernate.criterion.CriteriaSpecification.ALIAS_TO_ENTITY_MAP
            • 根据我的经验返回地图列表的性能很差。我更喜欢返回对象数组列表或 bean 列表(您始终可以定义适合您特定结果集的 bean)。
            【解决方案14】:
            • HQL 是对数据进行选择和非选择操作,但 Criteria 仅用于选择数据,我们不能使用条件进行非选择操作
            • HQL 适合执行静态查询,而 Criteria 适合执行动态查询
            • HQL 不支持分页概念,但我们可以通过 Criteria 实现分页
            • 执行条件过去比 HQL 需要更多时间
            • 使用 Criteria,我们可以安全地使用 SQL 注入,因为它会生成动态查询,但在 HQL 中,由于您的查询要么是固定的,要么是参数化的,因此无法避免 SQL 注入。

            source

            【讨论】:

            • 澄清一下,使用 Hibernate 的 Criteria API 的条件查询可能可用于查询,但 JPA 条件查询涵盖选择、更新和删除。请参阅CriteriaUpdate<T>CriteriaDelete<T> 以供参考。
            【解决方案15】:

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

            【讨论】:

            • 不是这样。使用 HQL,您可以使用 ':' 标识符设置属性,然后将这些属性替换为唯一值。例如,查询 q = session.createQuery("SELECT :aValue FROM my_table");然后 q.setParameter("aValue", "some_column_name");
            • @MattC 在您的示例中,您正在更改参数的值,而不是查询的结构。
            【解决方案16】:

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

            【讨论】:

              【解决方案17】:

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

              【讨论】:

                【解决方案18】:

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

                如果您深入研究并执行一些测试,您会发现标准查询比常规 HQL 执行得更好

                此外,使用 Criteria Query 您可以获得 面向对象的控制,而 HQL 则没有。

                有关更多信息,请阅读此答案here

                【讨论】:

                  【解决方案19】:

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

                  【讨论】:

                    【解决方案20】:

                    这篇文章很老了。大多数答案都是关于 Hibernate 标准,而不是 JPA 标准。 JPA 2.1 添加了 CriteriaDelete/CriteriaUpdate 和 EntityGraph 来控制要获取的确切内容。 Criteria API 更好,因为 Java 是 OO。这就是创建 JPA 的原因。 JPQL在编译的时候会先翻译成AST树(OO模型)再翻译成SQL。

                    【讨论】:

                      【解决方案21】:

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

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

                      例如,我使用 Criteria API 构建了 spring-data-jpa-mongodb-expressions(与 spring data QBE 一样)。

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

                      【讨论】:

                        【解决方案22】:

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

                        【讨论】:

                        • 这些问题不是HQL造成的,而是对基本的软件开发实践缺乏了解造成的。我也可以使用标准 api 创建容易受到 sql 注入攻击的代码。
                        • 这就像说“从 Java 查询 RDBMS 会导致 SQL 注入安全问题”:D
                        猜你喜欢
                        • 2011-08-25
                        • 2012-09-26
                        • 1970-01-01
                        • 1970-01-01
                        • 2015-02-23
                        • 2023-04-03
                        • 2012-05-03
                        • 1970-01-01
                        相关资源
                        最近更新 更多