Hibernate Named Query – Hibernate的命名查询

最后修改: 2018年 12月 8日

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

1. Overview

1.概述

A major disadvantage of having HQL and SQL scattered across data access objects is that it makes the code unreadable. Hence, it might make sense to group all HQL and SQL in one place and use only their reference in the actual data access code. Fortunately, Hibernate allows us to do this with named queries.

将HQL和SQL分散在数据访问对象中的一个主要缺点是,它使代码不可读。因此,将所有的HQL和SQL分组在一个地方,并在实际的数据访问代码中只使用它们的引用,可能是有意义的。幸运的是,Hibernate允许我们用命名查询来做到这一点。

A named query is a statically defined query with a predefined unchangeable query string. They’re validated when the session factory is created, thus making the application to fail fast in case of an error.

命名查询是一个静态定义的查询,有一个预定义的不可更改的查询字符串。它们在创建会话工厂时被验证,从而使应用程序在出现错误时快速失败。

In this article, we’ll see how to define and use Hibernate Named Queries using the @NamedQuery and @NamedNativeQuery annotations.

在本文中,我们将看到如何使用@NamedQuery@NamedNativeQuery注释来定义和使用Hibernate命名查询。

2. The Entity

2.实体

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

让我们首先看看我们在本文中要使用的实体。

@Entity
public class DeptEmployee {
    @Id
    @GeneratedValue(strategy = GenerationType.SEQUENCE)
    private long id;

    private String employeeNumber;

    private String designation;

    private String name;

    @ManyToOne
    private Department department;

    // getters and setters
}

In our example, we’ll retrieve an employee based on their employee number.

在我们的例子中,我们将根据雇员的编号来检索一个雇员。

3. Named Query

3.命名的查询

To define this as a named query, we’ll use the org.hibernate.annotations.NamedQuery annotation. It extends the javax.persistence.NamedQuery with Hibernate features.

为了将其定义为一个命名查询,我们将使用org.hibernate.annotations.NamedQueryannotation。它用Hibernate的特性扩展了javax.persistence.NamedQuery

We’ll define it as an annotation of the DeptEmployee class:

我们将把它定义为DeptEmployee类的一个注释。

@org.hibernate.annotations.NamedQuery(name = "DeptEmployee_findByEmployeeNumber", 
  query = "from DeptEmployee where employeeNumber = :employeeNo")

It’s important to note that every @NamedQuery annotation is attached to exactly one entity class or mapped superclass. But, since the scope of named queries is the entire persistence unit, we should select the query name carefully to avoid a collision. And we have achieved this by using the entity name as a prefix.

需要注意的是,每个@NamedQuery annotation都精确地附加到一个实体类或映射的超类上。但是, 由于命名查询的范围是整个持久化单元,我们应该仔细选择查询名称以避免碰撞。而我们通过使用实体名称作为前缀来实现这一点。

If we have more than one named query for an entity, we’ll use the @NamedQueries annotation to group these:

如果我们对一个实体有一个以上的命名查询,我们将使用@NamedQueries注解来分组这些。

@org.hibernate.annotations.NamedQueries({
    @org.hibernate.annotations.NamedQuery(name = "DeptEmployee_FindByEmployeeNumber", 
      query = "from DeptEmployee where employeeNumber = :employeeNo"),
    @org.hibernate.annotations.NamedQuery(name = "DeptEmployee_FindAllByDesgination", 
      query = "from DeptEmployee where designation = :designation"),
    @org.hibernate.annotations.NamedQuery(name = "DeptEmployee_UpdateEmployeeDepartment", 
      query = "Update DeptEmployee set department = :newDepartment where employeeNumber = :employeeNo"),
...
})

Note that the HQL query can be a DML-style operation. So, it doesn’t need to be a select statement only. For example, we can have an update query as in DeptEmployee_UpdateEmployeeDesignation above.

请注意,HQL查询可以是一个DML风格的操作。所以,它不需要只是一个选择语句。例如,我们可以有一个更新查询,如上面的DeptEmployee_UpdateEmployeeDesignation

3.1. Configuring Query Features

3.1.配置查询功能

We can set various query features with the @NamedQuery annotation. Let’s look at an example:

我们可以用@NamedQuery注释来设置各种查询功能。让我们看一个例子。

@org.hibernate.annotations.NamedQuery(
  name = "DeptEmployee_FindAllByDepartment", 
  query = "from DeptEmployee where department = :department",
  timeout = 1,
  fetchSize = 10
)

Here, we’ve configured the timeout interval and the fetch size. Apart from these two, we can also set features such as:

在这里,我们已经配置了超时间隔和取数大小。除了这两项之外,我们还可以设置一些功能,如。

  • cacheable – whether the query (results) is cacheable or not
  • cacheMode – the cache mode used for this query; this can be one of GET, IGNORE, NORMAL, PUT, or REFRESH
  • cacheRegion – if the query results are cacheable, name the query cache region to use
  • comment – a comment added to the generated SQL query; targetted for DBAs
  • flushMode – the flush mode for this query, one of ALWAYS, AUTO, COMMIT, MANUAL, or PERSISTENCE_CONTEXT

3.2. Using the Named Query

3.2.使用命名查询

Now that we’ve defined the named query, let’s use it to retrieve an employee:

现在我们已经定义了命名查询,让我们用它来检索一个雇员。

Query<DeptEmployee> query = session.createNamedQuery("DeptEmployee_FindByEmployeeNumber", 
  DeptEmployee.class);
query.setParameter("employeeNo", "001");
DeptEmployee result = query.getSingleResult();

Here, we’ve used the createNamedQuery method. It takes the name of the query and returns an org.hibernate.query.Query object.

这里,我们使用了createNamedQuery方法。它接收查询的名称并返回一个org.hibernate.query.Query对象。

4. Named Native Query

4.命名的本地查询

As well as HQL queries, we can also define native SQL as a named query. To do this, we can use the @NamedNativeQuery annotation. Though it is similar to the @NamedQuery, it requires a bit more configuration.

除了HQL查询,我们还可以将本地SQL定义为一个命名的查询。要做到这一点,我们可以使用@NamedNativeQuery注解。虽然它与@NamedQuery相似,但它需要更多的配置。

Let’s explore this annotation using an example:

让我们用一个例子来探讨这个注释。

@org.hibernate.annotations.NamedNativeQueries(
    @org.hibernate.annotations.NamedNativeQuery(name = "DeptEmployee_GetEmployeeByName", 
      query = "select * from deptemployee emp where name=:name",
      resultClass = DeptEmployee.class)
)

Since this is a native query, we’ll have to tell Hibernate what entity class to map the results to. Consequently, we’ve used the resultClass property for doing this.

由于这是一个本地查询,我们必须告诉Hibernate要将结果映射到哪个实体类。因此,我们使用了resultClass属性来完成这个任务。

Another way to map the results is to use the resultSetMapping property. Here, we can specify the name of a pre-defined SQLResultSetMapping.

另一种映射结果的方法是使用resultSetMapping属性。在这里,我们可以指定一个预先定义的SQLResultSetMapping的名称。

Note that we can use only one of resultClass and resultSetMapping.

注意,我们只能使用resultClassresultSetMapping中的一个。

4.1. Using the Named Native Query

4.1.使用命名的本地查询

To use the named native query, we can use the Session.createNamedQuery():

要使用命名的本地查询,我们可以使用Session.createNamedQuery()

Query<DeptEmployee> query = session.createNamedQuery("DeptEmployee_FindByEmployeeName", DeptEmployee.class);
query.setParameter("name", "John Wayne");
DeptEmployee result = query.getSingleResult();

Or the Session.getNamedNativeQuery():

Session.getNamedNativeQuery()

NativeQuery query = session.getNamedNativeQuery("DeptEmployee_FindByEmployeeName");
query.setParameter("name", "John Wayne");
DeptEmployee result = (DeptEmployee) query.getSingleResult();

The only difference between these two approaches is the return type. The second approach returns a NativeQuery, which is a subclass of Query.

这两种方法的唯一区别是返回类型。第二种方法返回一个NativeQuery,它是Query的一个子类。

5. Stored Procedures and Functions

5.存储程序和函数

We can use the @NamedNativeQuery annotation to define calls to stored procedures and functions as well:

我们也可以使用@NamedNativeQuery注解来定义对存储过程和函数的调用。

@org.hibernate.annotations.NamedNativeQuery(
  name = "DeptEmployee_UpdateEmployeeDesignation", 
  query = "call UPDATE_EMPLOYEE_DESIGNATION(:employeeNumber, :newDesignation)", 
  resultClass = DeptEmployee.class)

Notice that although this is an update query, we’ve used the resultClass property. This is because Hibernate doesn’t support pure native scalar queries. And the way to work around the problem is to either set a resultClass or a resultSetMapping.

注意,虽然这是一个更新查询,但我们使用了resultClass属性。这是因为Hibernate不支持纯本地标量查询。而解决这个问题的方法是设置一个resultClass或者一个resultSetMapping.

6. Conclusion

6.结论

In this article, we saw how to define and use named HQL and native queries.

在这篇文章中,我们看到如何定义和使用命名的HQL和本地查询。

The source code is available over on GitHub.

源代码可在GitHub上获得