I already explained the 2nd and 3rd options in previous articles. In this tutorial, I want to focus on the first option: the referencing of a named native or JPQL query in a Spring Data JPA repository. It makes executing your query much easier because Spring Data takes care of all the boilerplate code required by JPA.

Defining a Named Query with JPA

Named queries are one of the core concepts in JPA. They enable you to declare a query in your persistence layer and reference it in your business code. That makes it easy to reuse an existing query. It also enables you to separate the definition of your query from your business code.

You can define a named query using a @NamedQuery annotation on an entity class or using a <named-query /> element in your XML mapping. In this article, I will show you the annotation-based mapping. It’s the by far the most common approach to creating a named query.

When you define a named query, you can provide a JPQL query or a native SQL query in very similar ways. Let’s take a look at both options.

Defining a Named JPL Query

The JPA specification defines its own query language. It’s called JPQL, and its syntax is similar to SQL. But there are 2 essential differences between these 2:

You define your JPQL query based on your entity model. When you execute it, your persistence provider generates a SQL query based on your entity mappings and the provided JPQL statement. That enables you to define database-independent queries but also limits you to the features supported by your persistence provider.

JPQL supports only a small subset of the SQL standard and almost no database-specific features.

The definition of a named JPQL query is pretty simple. You just have to annotate one of your entity classes with @NamedQuery and provide 2 Strings for the name and query attributes.

The name of your query has to be unique within your persistence context. You will use it in your business code or repository definition to reference the query.

The name doesn’t have to follow any conventions if you want to reference the query programmatically. But if you’re going to reference it in a Spring Data JPA repository, the name should start with the name of the entity class, followed by a “.” and the name of the repository method.

The value of the query attribute has to be a String that contains a valid JPQL statement. If your query returns an entity, you can define your projection implicitly, as you can see in the Author.findByFirstName query. The Author.findByFirstNameAndLastName query contains a SELECT clause to define the projection explicitly.

If you want to define multiple JPQL queries and use at least JPA 2.2 or Hibernate 5.2, you can annotate your class with multiple @NamedQuery annotations. If you are using an older JPA or Hibernate version, you need to wrap your @NamedQuery annotation within a @NamedQueries annotation.

Defining a Named Native Query

Native SQL queries are more powerful and flexible than JPQL queries. Your persistence provider doesn’t parse these queries and sends them directly to the database. That enables you to use all SQL features supported by your database. But you also have to handle the different database dialects if you need to support multiple DBMS.

You can define a named native query in almost the same way as you specify a named JPQL query. The 3 main differences are:

You need to use a @NamedNativeQuery instead of a @NamedQuery annotation.

The value of the query attribute has to be an SQL statement instead of a JPQL statement.

You can define an entity class or a reference to an @SqlResultSetMapping that will be used to map the result of your query. Spring Data JPA can provide a set of default mappings so that you often don’t need to specify it.

Here you can see the same queries as in the previous example. But this time, they are defined as native SQL queries instead of JPQL queries.

Before you run this code, you should activate the logging of SQL statements. You can then see the executed SQL statement and the used bind parameter values in your log file. In this example, I called the @NamedNativeQuery version of the previously shown Author.findByFirstName query.

Referencing a Named Query in a Spring Data JPA repository

As you have seen in the previous example, executing a named query using JPA’s EntityManager isn’t complicated, but it requires multiple steps.

Spring Data JPA takes care of that if you reference a named query in your repository definition. Doing that is extremely simple if you follow Spring Data’s naming convention. The name of your query has to start with the name of your entity class, followed by “.” and the name of your repository method.

In the previous examples, I defined the named queries Author.findByFirstName and Author.findByFirstNameAndLastName as JPQL and native queries. You can reference both versions of these queries by adding the methods findByFirstName and findByFirstNameAndLastName to the AuthorRepository.

You can then inject an AuthorRepository instance in your business code and call the repository methods to execute the named queries.

As you can see in the following code snippet, you can use these repository methods in the same way as a repository method that executes a derived query or a declared query. Spring Data JPA handles the instantiation of the named query, sets the bind parameter values, executes the query, and maps the result.

Conclusion

Named queries are one of the various options to query data from your database that are defined by the JPA specification.

Spring Data JPA provides a very comfortable way to use named queries in your repository. It takes care of all the repetitive boilerplate code required by the JPA specification. By default, Spring Data JPA checks for a named JPQL or a named native query that follows the naming convention <entity class name>.<repository method name> before it tries to derive a query from the method name.