JPA and Hibernate – Criteria vs. JPQL vs. HQL Query – JPA和Hibernate – Criteria vs. JPQL vs. HQL查询

最后修改: 2022年 5月 8日

中文/混合/英文(键盘快捷键:t)

1. Overview

1.概述

In this tutorial, we’ll see how to use JPA and Hibernate queries and the difference between Criteria, JPQL, and HQL queries. Criteria queries enable the user to write queries without using raw SQL. Along with Criteria queries, we’ll explore writing Hibernate Named Queries and how to use the @Query annotation in Spring Data JPA.

在本教程中,我们将看到如何使用JPA和Hibernate查询以及Criteria、JPQL和HQL查询之间的区别。Criteria查询使用户可以在不使用原始SQL的情况下编写查询。除了标准查询,我们还将探讨如何编写Hibernate命名查询以及如何在Spring Data JPA中使用@Query注释。

Before we dive in, we should note that the Hibernate Criteria API has been deprecated since Hibernate 5.2. Therefore, we’ll be using the JPA Criteria API in our examples, as it’s the new and preferred tool for writing Criteria queries. So, from here on, we’ll refer to it simply as the Criteria API.

在我们深入研究之前,我们应该注意到,自Hibernate 5.2以来,Hibernate Criteria API已被废弃。因此,我们将在示例中使用JPA Criteria API,因为它是编写 Criteria 查询的新的首选工具。因此,从这里开始,我们将把它简单地称为Criteria API。

2. Criteria Queries

2.标准查询

The Criteria API helps in building the Criteria query object by applying different filters and logical conditions on top of it. This is an alternate way to manipulate objects and return the desired data from an RDBMS table.

Criteria API通过在上面应用不同的过滤器和逻辑条件来帮助构建Criteria查询对象。这是一种操作对象并从RDBMS表中返回所需数据的替代方法。

The createCriteria() method from the Hibernate Session returns the persistence object instance for running a criteria query in the application. Simply put, the Criteria API builds up a criteria query that applies different filters and logical conditions.

来自Hibernate SessioncreateCriteria()方法返回持久化对象实例,用于在应用程序中运行一个标准查询。简单地说,Criteria API建立了一个标准查询,应用不同的过滤器和逻辑条件。

2.1. Maven Dependencies

2.1.Maven的依赖性

Let’s grab the latest version of the reference JPA dependency – which implements JPA in Hibernate – and add it to our pom.xml:

让我们抓取最新版本的参考JPA依赖性–它在Hibernate中实现了JPA–并将其添加到我们的pom.xml

<dependency>
    <groupId>org.hibernate</groupId>
    <artifactId>hibernate-core</artifactId>
    <version>5.3.2.Final</version>
</dependency>

2.2. Using the Criteria Queries and Expressions

2.2.使用标准查询和表达式

As per the user’s conditions, CriteriaBuilder controls the query results. It uses the where() method from CriteriaQuery, which provides CriteriaBuilder expressions.

根据用户的条件,CriteriaBuilder控制查询结果。它使用CriteriaQuery中的where()方法,该方法提供CriteriaBuilder表达式。

Let’s look at the entity we’ll be using in this article:

让我们来看看我们将在本文中使用的实体。

public class Employee {

    private Integer id;
    private String name;
    private Long salary;

   // standard getters and setters
}

Let’s look at a simple criteria query that will retrieve all the rows of “Employee” from the database:

让我们看看一个简单的标准查询,它将从数据库中检索出“Employee”的所有行。

Session session = HibernateUtil.getHibernateSession();
CriteriaBuilder cb = session.getCriteriaBuilder();
CriteriaQuery<Employee> cr = cb.createQuery(Employee.class);
Root<Employee> root = cr.from(Employee.class);
cr.select(root);

Query<Employee> query = session.createQuery(cr);
List<Employee> results = query.getResultList();
session.close();
return results;

The above Criteria query returns a set of all the items. Let’s see how it happens:

上面的Criteria查询返回一个所有项目的集合。让我们看看它是如何发生的。

  1. The SessionFactory object creates the Session instance
  2. The Session returns an instance of CriteriaBuilder using the getCriteriaBuilder() method
  3. The CriteriaBuilder uses the createQuery() method. This creates the CriteriaQuery() object that further returns the Query instance
  4. In the end, we call the getResult() method to obtain the query object that holds the results

Let’s look at another expression from CriteriaQuery:

让我们看一下CriteriaQuery的另一个表达式。

cr.select(root).where(cb.gt(root.get("salary"), 50000));

For its result, the above query returns the set of employees having a salary of more than 50000.

就其结果而言,上述查询返回工资超过50000的员工集合。

3. JPQL

3.JPQL

JPQL stands for Java Persistence Query Language. Spring Data provides multiple ways to create and execute a query, and JPQL is one of these. It defines queries using the @Query annotation in Spring to execute both JPQL and native SQL queries. The query definition uses JPQL by default.

JPQL代表Java Persistence查询语言。Spring Data提供了多种创建和执行查询的方法,而JPQL就是其中之一。它使用Spring中的@Query注解来定义查询,以执行JPQL和本地SQL查询。查询定义默认使用JPQL。

We use the @Query annotation to define a SQL query in Spring. Any query defined by the @Query annotation has higher priority over named queries, which are annotated with @NamedQuery.

我们使用@Query注解来定义Spring中的SQL查询。任何由@Query注解定义的查询都比用@NamedQuery注解的命名查询具有更高的优先级

3.1. Using JPQL Queries

3.1.使用JPQL查询

Let’s build a dynamic query using JPQL:

让我们使用JPQL建立一个动态查询。

@Query(value = "SELECT e FROM Employee e")
List<Employee> findAllEmployees(Sort sort);

With JPQL queries that have argument parameters, Spring Data passes the method arguments to the query in the same order as the method declaration. Let’s look at a couple of examples that pass method arguments into the query:

对于有参数的JPQL查询,Spring Data以与方法声明相同的顺序将方法参数传递到查询中。让我们来看看几个将方法参数传递到查询中的例子。

@Query("SELECT e FROM Employee e WHERE e.salary = ?1")
Employee findAllEmployeesWithSalary(Long salary);
@Query("SELECT e FROM Employee e WHERE e.name = ?1 and e.salary = ?2")
Employee findEmployeeByNameAndSalary(String name, Long salary);

For the latter query above, the name method argument is passed as the query parameter with respect to index 1, and the salary argument is passed as the index 2 query parameter.

对于上面的后一个查询,name方法参数被传递为与索引1有关的查询参数,而salary参数被传递为索引2的查询参数。

3.2. Using the JPQL Native Queries

3.2.使用JPQL本地查询

We can execute these SQL queries directly in our databases using native queries, which refer to real databases and table objects. We need to set the value of the nativeQuery attribute to true for defining a native SQL query. The native SQL query will be defined in the value attribute of the annotation.

我们可以使用本地查询在我们的数据库中直接执行这些SQL查询,它引用了真实的数据库和表对象。我们需要nativeQuery属性的值设置为true,以定义一个本地SQL查询本地SQL查询将被定义在注释的value属性中。

Let’s see a native query that shows an indexed parameter to be passed as an argument for the query:

让我们看看一个本地查询,它显示了一个要作为查询参数传递的索引参数。

@Query(
  value = "SELECT * FROM Employee e WHERE e.salary = ?1",
  nativeQuery = true)
Employee findEmployeeBySalaryNative(Long salary);

Using Named Parameters makes the query easier to read and less error-prone in the case of refactoring. Let’s see an illustration of a simple Named Query in JPQL and native format:

使用命名参数使查询更容易阅读,并且在重构的情况下更不容易出错。让我们看看一个JPQL和本地格式的简单命名查询的说明。

@Query("SELECT e FROM Employee e WHERE e.name = :name and e.salary = :salary")
Employee findEmployeeByNameAndSalaryNamedParameters(
  @Param("name") String name,
  @Param("salary") Long salary);

The method parameters are passed to the query using named parameters. We can define named queries by using the @Param annotation inside the repository method declaration. As a result, the @Param annotation must have a string value that matches the corresponding JPQL or SQL query name.

方法参数使用命名参数传递给查询。我们可以通过在存储库方法声明中使用@Param注解来定义命名查询。因此,@Param注解必须有一个字符串值,与相应的JPQL或SQL查询名称相匹配。

@Query(value = "SELECT * FROM Employee e WHERE e.name = :name and e.salary = :salary", 
  nativeQuery = true) 
Employee findUserByNameAndSalaryNamedParamsNative( 
  @Param("name") String name, 
  @Param("salary") Long salary);

4. HQL

4.HQL

HQL stands for Hibernate Query Language. It’s an object-oriented language similar to SQL that we can use to query our database. However, the main disadvantage is the code’s unreadability. We can define our queries as Named Queries to place them in the actual code that accesses the database.

HQL代表Hibernate查询语言。它是一种类似于SQL的面向对象的语言,我们可以用它来查询我们的数据库。然而,其主要的缺点是代码的不可读性。我们可以将我们的查询定义为 “命名查询”,以便将它们放在访问数据库的实际代码中。

4.1. Using Hibernate Named Query

4.1.使用Hibernate的命名查询

A Named Query defines a query with a predefined, unchangeable query string. These queries are fail-fast since they’re validated during the creation of the session factory. Let’s define a Named Query using the org.hibernate.annotations.NamedQuery annotation:

Named Query定义了一个具有预定义的、不可更改的查询字符串的查询。这些查询是快速失败的,因为它们在创建会话工厂的过程中被验证。让我们使用org.hibernate.annotations.NamedQuery注解来定义Named Query。

@NamedQuery(name = "Employee_FindByEmployeeId",
 query = "from Employee where id = :id")

Each @NamedQuery annotation attaches itself to one entity class only. We can use the @NamedQueries annotation to group more than one named query for an entity:

每个@NamedQuery注解都只附着在一个实体类上。我们可以使用@NamedQueries注解来为一个实体分组一个以上的命名查询。

@NamedQueries({
    @NamedQuery(name = "Employee_findByEmployeeId", 
      query = "from Employee where id = :id"),
    @NamedQuery(name = "Employee_findAllByEmployeeSalary", 
      query = "from Employee where salary = :salary")
})

4.2. Stored Procedures and Expressions

4.2.存储程序和表达式

In conclusion, we can use the @NamedNativeQuery annotation for storing the procedures and functions:

总之,我们可以使用@NamedNativeQuery注解来存储存储过程和函数。

@NamedNativeQuery(
  name = "Employee_FindByEmployeeId", 
  query = "select * from employee emp where id=:id", 
  resultClass = Employee.class)

5. Advantages of Criteria Queries Over HQL and JPQL Queries

5.标准查询比HQL和JPQL查询的优势

The main advantage of Criteria Queries over HQL is the nice, clean, object-oriented API. As a result, we can detect errors in Criteria API during the compile time.

与HQL相比,Criteria查询的主要优势是漂亮、干净、面向对象的API。因此,我们可以在编译时检测Criteria API中的错误。

In addition, JPQL queries and Criteria queries have the same performance and efficiency.

此外,JPQL查询和Criteria查询具有相同的性能和效率。

Criteria queries are more flexible and provide better support for writing dynamic queries as compared to HQL and JPQL.

与HQL和JPQL相比,标准查询更加灵活,为编写动态查询提供更好的支持。

But HQL and JPQL provide native query support that isn’t possible with the Criteria queries. This is one of the disadvantages of the Criteria query.

但是,HQL和JPQL提供了本机查询支持,这在Criteria查询中是不可能的。这是Criteria查询的缺点之一。

We can easily write complex joins using JPQL native queries, whereas it gets difficult to manage while applying the same with Criteria API.

我们可以很容易地使用JPQL本地查询编写复杂的连接而在使用Criteria API时,就很难管理。

6. Conclusion

6.结语

In this article, we mainly looked at the basics of Criteria queries, JPQL queries, and the HQL queries in Hibernate and JPA. In addition, we learned how to use these queries and the advantages and disadvantages of each approach.

在这篇文章中,我们主要研究了Hibernate和JPA中的Criteria查询、JPQL查询和HQL查询的基础知识。此外,我们还学习了如何使用这些查询以及每种方法的优缺点。

As always, the complete code examples used in this article can be found over on GitHub and here.

一如既往,本文中使用的完整代码示例可以在GitHub上找到over,以及here