Hibernate Named Query Examples

A named query is a static HQL or SQL query with a fixed query string and defined either using @NamedQuery annotation or an XML file. We can refer to a named query by its name, in the runtime, when we need to execute it.

Note that Hibernate’s @NamedQuery annotation extends JPA’s @NamedQuery annotation with some additional features.

1. Advantages

The named queries help in grouping the HQL statements in a single place and lately refer to them using pre-configured names whenever we need to use them. This grouping helps largely in code cleanup because these HQL statements are no longer scattered in the whole code.

Apart from the above, there are some more advantages of named queries:

  1. Fail fast: query syntaxes are checked when the SessionFactory is created, making the application fail fast in case of an error.
  2. Reusable: These can be accessed and used from several places in the application which increases re-usability.

Performance-wise named queries do not make much difference, nor put any excessive cost.

  1. The cost of transforming an HQL query to SQL is negligible compared to the cost of actually executing the query.
  2. The memory cost of caching the queries is really small. Remember that Hibernate needs to have all the entities’ meta-data in memory anyway.

2. Creating @NamedQuery

To demonstrate how to declare a named query, we have the DepartmentEntity. We are creating a simple named query that fetches a department by its id.

Named query definition has two important attributes:

  • name: The name of the named query by which it will be located using the Session or EntityManager interface.
  • query: The HQL or SQL statement to get executed in the database.
@NamedQuery(name = "QUERY_GET_DEPARTMENT_BY_ID",
    query = DepartmentEntity.QUERY_GET_DEPARTMENT_BY_ID)
@Entity
public class DepartmentEntity implements Serializable {

  //Constant to refer the query name in other places
  public static final String QUERY_GET_DEPARTMENT_BY_ID
      = "QUERY_GET_DEPARTMENT_BY_ID";

  @Id
  @GeneratedValue(strategy = GenerationType.IDENTITY)
  private Integer id;

  private String name;

  //Setters and getters are hidden for brevity
}

Additionally, we can supply more configuration attributes as per our requirements.

@NamedQuery(name = "QUERY_GET_DEPARTMENT_BY_ID",
    query = "from DepartmentEntity d where d.id = :id",
    cacheable = true,
    fetchSize = 1,
    timeout = 1,
    readOnly = true)

3. Grouping with @NamedQueries

If we have multiple named queries for an entity we can group them using the @NamedQueries annotation.

@NamedQueries({
    @NamedQuery(name = "QUERY_GET_DEPARTMENT_BY_ID",
        query = "from DepartmentEntity d where d.id = :id"),
    @NamedQuery(name = "QUERY_UPDATE_DEPARTMENT_BY_ID",
        query = "UPDATE DepartmentEntity d SET d.name=:name where d.id = :id")
})
@Entity
public class DepartmentEntity implements Serializable {

  public static final String QUERY_GET_DEPARTMENT_BY_ID
      = "QUERY_GET_DEPARTMENT_BY_ID";

  public static final String QUERY_UPDATE_DEPARTMENT_BY_ID
      = "QUERY_UPDATE_DEPARTMENT_BY_ID";

  //...
}

4. Executing a Named Query

To execute a named query, we can use the createNamedQuery() method that creates a Query instance. Then we can use a method from Query interface to execute the SQL query.

  @Test
  public void getEntityById() {
    Query query =
        em.createNamedQuery(DepartmentEntity.QUERY_GET_DEPARTMENT_BY_ID)
            .setParameter("id", 1);

    DepartmentEntity dept = (DepartmentEntity) query.getSingleResult();

    Assertions.assertEquals("HR", dept.getName());
  }

5. Using @NamedNativeQuery

The @NamedNativeQuery works very similar to @NamedQuery except we need to write the native SQL statements instead of HQL.

@NamedNativeQueries({
    @NamedNativeQuery(name = "NATIVE_QUERY_GET_DEPARTMENT_BY_ID",
        query = "SELECT * FROM TBL_DEPT d WHERE d.id = :id"),
    @NamedNativeQuery(name = "NATIVE_QUERY_UPDATE_DEPARTMENT_BY_ID",
        query = "UPDATE TBL_DEPT d SET d.name=:name WHERE d.id = :id")
})

The execution of named native queries is pretty much similar to the named queries.

  @Test
  public void updateEntityByIdWithNamedNativeQuery() {
    Query query =
        em.createNamedQuery(DepartmentEntity.NATIVE_QUERY_UPDATE_DEPARTMENT_BY_ID)
            .setParameter("name", "SUPPORT")
            .setParameter("id", 1);

    query.executeUpdate();
    flushAndClear();

    DepartmentEntity dept = em.find(DepartmentEntity.class, 1);

    Assertions.assertEquals("SUPPORT", dept.getName());
  }

6. Conclusion

In this tutorial, we learned to create, group and execute named queries using hibernate. As a best practice we should:

  • Use native queries preferably only for selecting records based on complex conditions. Do not use them excessively, otherwise, there is no use of using ORM over simple JDBC.
  • Remember that result of named queries is not cached in the secondary cache, only the query object itself gets cached.
  • Make a habit of adding a couple of unit testcases whenever we add any named query in code. And run those unit testcases immediately.
  • Fortunately, we can not have two named queries with the same name in hibernate. Hibernate shows fail-fast behavior in this regard and will show errors in the application start-up itself.

Happy Learning !!

Sourcecode on Github

Comments

Subscribe
Notify of
guest
9 Comments
Most Voted
Newest Oldest
Inline Feedbacks
View all comments

About Us

HowToDoInJava provides tutorials and how-to guides on Java and related technologies.

It also shares the best practices, algorithms & solutions and frequently asked interview questions.

Our Blogs

REST API Tutorial

Dark Mode

Dark Mode