Skip to content

When Should You Use nativeQuery=true in Spring Data JPA @Query Annotations

Problem

When I wrote a SQL query in a @Query annotation, I got this error:

Query validation error
Caused by: java.lang.IllegalArgumentException:
Validation failed for query for method
public abstract java.util.List com.example.repository.UserRepository.findActiveUsers()
Caused by: org.hibernate.hql.internal.ast.QuerySyntaxException:
unexpected token: * near line 1, column 8 [SELECT * FROM users WHERE status = 1]

I just wanted to run a simple SQL query. Why was Spring trying to parse it as JPQL?

Environment

  • Spring Boot 3.2.x
  • Spring Data JPA 3.2.x
  • PostgreSQL database
  • Hibernate as JPA provider

What happened?

I wrote what I thought was a straightforward query:

UserRepository.java - Problem
@Repository
public interface UserRepository extends JpaRepository<User, Long> {
@Query("SELECT * FROM users WHERE status = 1")
List<User> findActiveUsers();
}

The error occurred because Spring Data JPA parses all @Query annotations as JPQL by default. My query used SQL syntax (SELECT * FROM users), not JPQL syntax (SELECT u FROM User u).

How to solve it?

Add nativeQuery = true to tell Spring to treat the query as raw SQL:

UserRepository.java - Solution
@Repository
public interface UserRepository extends JpaRepository<User, Long> {
@Query(value = "SELECT * FROM users WHERE status = 1", nativeQuery = true)
List<User> findActiveUsers();
}

Now the query bypasses JPQL validation and executes directly against the database.

When to use JPQL vs native SQL

Here’s how I decide:

Use JPQL (default) for:

JPQL examples
// Standard entity queries - database agnostic
@Query("SELECT u FROM User u WHERE u.status = :status")
List<User> findByStatus(@Param("status") Integer status);
// Joins between entities
@Query("SELECT u FROM User u JOIN u.orders o WHERE o.total > 1000")
List<User> findUsersWithLargeOrders();
// Aggregations
@Query("SELECT COUNT(u) FROM User u WHERE u.active = true")
Long countActiveUsers();

Use native SQL (nativeQuery = true) for:

Native SQL examples
// Database-specific functions
@Query(value = "SELECT * FROM users WHERE created_at > NOW() - INTERVAL '7 days'", nativeQuery = true)
List<User> findRecentUsers();
// Complex SQL that JPQL doesn't support
@Query(value = "SELECT u.* FROM users u JOIN orders o ON u.id = o.user_id WHERE o.total > 1000", nativeQuery = true)
List<User> findUsersWithLargeOrders();
// Raw SQL for performance optimization
@Query(value = "SELECT * FROM users WHERE id IN (SELECT user_id FROM orders GROUP BY user_id HAVING COUNT(*) > 10)", nativeQuery = true)
List<User> findUsersWithManyOrders();
// Working with existing SQL queries
@Query(value = "SELECT * FROM users WHERE status = 1", nativeQuery = true)
List<User> findActiveUsers();

Key differences

AspectJPQLNative SQL
SyntaxEntity/field namesTable/column names
PortabilityDatabase-agnosticDatabase-specific
ValidationAt startupAt runtime
Type safetyCompile-time hintsNone
FeaturesLimited to JPA specFull SQL power

Test verification

Test
@Test
void givenActiveUser_whenFindActiveUsers_thenReturnsUser() {
User user = new User();
user.setFirstName("Jane");
user.setStatus(1);
userRepository.save(user);
List<User> result = userRepository.findActiveUsers();
assertEquals(1, result.size());
assertEquals(1, result.get(0).getStatus());
}

Summary

In this post, I explained when to use nativeQuery = true in Spring Data JPA. The key point is that JPQL (default) queries Java entities and is database-agnostic, while native SQL queries database tables directly.

Use native SQL when you need database-specific features, complex SQL, or are working with existing queries. Use JPQL for standard entity operations to maintain database portability.

Final Words + More Resources

My intention with this article was to help others share my knowledge and experience. If you want to contact me, you can contact by email: Email me

Here are also the most important links from this article along with some further resources that will help you in this scope:

Oh, and if you found these resources useful, don’t forget to support me by starring the repo on GitHub!

Comments