Named Queries in JPA: Mastering @NamedQuery and @NamedNativeQuery with Examples

Illustration for Named Queries in JPA: Mastering @NamedQuery and @NamedNativeQuery with Examples
By Last updated:

In real-world applications, database queries are rarely one-off operations. Instead, they are often reused across different layers of the system. Writing dynamic queries every time leads to code duplication, performance issues, and maintainability problems.

To solve this, JPA provides Named Queries — predefined, reusable queries declared at the entity level. These queries are compiled when the application starts, improving performance and reducing runtime errors.

In this tutorial, we’ll explore @NamedQuery (for JPQL) and @NamedNativeQuery (for SQL), their configurations, CRUD operations, and best practices.


What are Named Queries?

A Named Query is a statically defined query associated with an entity.

  • @NamedQuery → Defines a JPQL query.
  • @NamedNativeQuery → Defines a SQL query (native to the database).

Both can be defined at the entity class level and invoked by name at runtime.


Entity Setup Example

import jakarta.persistence.*;

@Entity
@Table(name = "employees")
@NamedQueries({
    @NamedQuery(
        name = "Employee.findAll",
        query = "SELECT e FROM Employee e"
    ),
    @NamedQuery(
        name = "Employee.findByDepartment",
        query = "SELECT e FROM Employee e WHERE e.department = :dept"
    )
})
@NamedNativeQueries({
    @NamedNativeQuery(
        name = "Employee.findBySalaryRange",
        query = "SELECT * FROM employees WHERE salary BETWEEN ?1 AND ?2",
        resultClass = Employee.class
    )
})
public class Employee {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private String name;
    private String department;
    private Double salary;
}

Using Named Queries with EntityManager

1. Invoking a @NamedQuery

List<Employee> employees = entityManager
    .createNamedQuery("Employee.findAll", Employee.class)
    .getResultList();

2. Using Parameters in Named Query

List<Employee> hrEmployees = entityManager
    .createNamedQuery("Employee.findByDepartment", Employee.class)
    .setParameter("dept", "HR")
    .getResultList();

3. Invoking a @NamedNativeQuery

List<Employee> employees = entityManager
    .createNamedQuery("Employee.findBySalaryRange", Employee.class)
    .setParameter(1, 50000.0)
    .setParameter(2, 100000.0)
    .getResultList();

CRUD Operations with Named Queries

Create (Persist)

Employee emp = new Employee();
emp.setName("Alice");
emp.setDepartment("Finance");
emp.setSalary(80000.0);

entityManager.getTransaction().begin();
entityManager.persist(emp);
entityManager.getTransaction().commit();

Read with Named Query

List<Employee> financeEmployees = entityManager
    .createNamedQuery("Employee.findByDepartment", Employee.class)
    .setParameter("dept", "Finance")
    .getResultList();

Update Example

entityManager.getTransaction().begin();
emp.setSalary(90000.0);
entityManager.merge(emp);
entityManager.getTransaction().commit();

Delete Example

entityManager.getTransaction().begin();
entityManager.remove(emp);
entityManager.getTransaction().commit();

Real-World Use Cases

  • Enterprise Applications → Predefined queries for frequently accessed data (users, orders, employees).
  • Microservices → Shared queries across service boundaries.
  • Performance Optimization → Queries validated and compiled at startup.

Anti-Patterns and Pitfalls

  • Overloading entities with too many named queries → reduces readability.
  • Using native queries without mapping resultClass → may cause runtime errors.
  • Forgetting to use parameters in native queries → risk of SQL injection.

Best Practices

  • Use @NamedQuery for JPQL portability across databases.
  • Use @NamedNativeQuery only when JPQL cannot express the query.
  • Prefer constants for query names to avoid typos.
  • Organize queries logically across entities.

📌 JPA Version Notes

  • JPA 2.0 → Enhanced JPQL, Criteria API.
  • JPA 2.1 → Added entity graphs, stored procedures.
  • JPA 2.2 → Improved Java 8 Date/Time API support.
  • Jakarta Persistence (EE 9/10/11) → Package renamed from javax.persistencejakarta.persistence.

Conclusion and Key Takeaways

  • Named Queries are predefined JPQL or SQL queries associated with entities.
  • @NamedQuery is database-independent, while @NamedNativeQuery executes raw SQL.
  • They improve reusability, performance, and maintainability.
  • Always prefer JPQL-based named queries unless native SQL is absolutely required.

FAQ: Expert-Level Questions

1. What’s the difference between JPA and Hibernate?
JPA is a specification; Hibernate is its implementation.

2. How does JPA handle the persistence context?
It’s like a classroom attendance register, tracking all managed entities.

3. What are the drawbacks of eager fetching in JPA?
It loads unnecessary associations, hurting performance.

4. How can I solve the N+1 select problem with JPA?
Use JOIN FETCH, entity graphs, or batch fetching.

5. Can I use JPA without Hibernate?
Yes, alternatives include EclipseLink, OpenJPA, and DataNucleus.

6. What’s the best strategy for inheritance mapping in JPA?
Depends: SINGLE_TABLE, JOINED, or TABLE_PER_CLASS.

7. How does JPA handle composite keys?
Using @IdClass or @EmbeddedId.

8. What changes with Jakarta Persistence?
Package renamed to jakarta.persistence.

9. Is JPA suitable for microservices?
Yes, but in high-performance cases, lightweight alternatives may be better.

10. When should I avoid using JPA?
For batch-heavy, complex reporting, or ultra-low latency applications.