Native Queries in Spring Data JPA : @Query Annotation

pring Data JPA is powerful. In most cases, you can get away with method naming conventions like findByUsername, or using derived queries. But sometimes, you need more control β€” like using custom SQL or JPQL (Java Persistence Query Language).

This is where the @Query annotation and native queries in Spring Data come in.

Native Queries in Spring Data JPA

🧠 What You’ll Learn

  • What is the @Query annotation?
  • Difference between JPQL and native SQL
  • How to write native queries
  • Named parameters, pagination, projections
  • Best practices

πŸ” What is the @Query Annotation?

Spring Data JPA allows you to define custom queries using the @Query annotation in repository interfaces.

You can write:

  • JPQL (uses entity names and field names)
  • Native SQL (directly uses table and column names)

πŸ”„ JPQL vs Native SQL

FeatureJPQLNative SQL
Based OnEntity classesDatabase tables
PortableYesNo (DB-specific syntax)
Uses@Query (default)@Query(..., nativeQuery = true)
ExampleSELECT u FROM User uSELECT * FROM users

πŸ§ͺ 1. Writing a JPQL Query with @Query

Suppose we have this entity:

Now in the UserRepository:

You can also use named parameters:

πŸ› οΈ 2. Writing a Native Query

Use nativeQuery = true to write raw SQL.

Or with named parameters:

πŸ” 3. Returning a List of Results

For native:

πŸ“„ 4. DTO Projection from Native Query

Instead of returning entities, you can project selected fields into a DTO:

DTO

Query

βœ… This is constructor-based projection in JPQL.

For native SQL, use an interface projection:

Interface DTO

Query

⏳ 5. Pagination with @Query

Use Pageable as a parameter.

🚨 6. Update or Delete with @Query

You must add @Modifying and @Transactional.

For Delete:

βœ… Best Practices

TipReason
Use JPQL over native when possibleJPQL is portable and safer
Use named parametersImproves readability
Keep native SQL in a separate file for complex queriesEasier to maintain
Always test native queries against DB schemaDB syntax may vary
Use projections (DTOs/interfaces) when full entity isn’t neededImproves performance
Use @Modifying and @Transactional for updates/deletesRequired for data-chang

🧹 Summary

Use CaseAnnotation
Read query with JPQL@Query("SELECT u FROM User u")
Read query with SQL@Query(..., nativeQuery = true)
Update/DeleteAdd @Modifying and @Transactional
Return DTOUse constructor or interface projection
Add paginationInclude Pageable parameter

Reference

JPA Query Methods