JPQL and Native Queries
JPQL and Native Queries
You are not limited to derived method names. For complex reporting, JPQL expresses queries against entities with an SQL-like syntax, and native SQL handles the cases where only the database's own features will do.
JPQL works on entities
JPQL selects from entity names and navigates fields, so the database schema can change without rewriting your queries. This snippet fetches recent published posts, proving that joins read like plain object navigation.
@Query("SELECT p FROM Post p WHERE p.published = true " +
"ORDER BY p.publishedAt DESC")
List<Post> findPublished();
Parameters and pagination
Bind parameters with :name rather than concatenating user input to avoid injection. Add sorting and limits at the method level with Pageable, so one query method supports several pages.
Native queries
Native SQL bypasses JPQL for database-specific SQL, window functions, or full-text search. Mark the method with nativeQuery = true and add a mapping to objects. Prefer JPQL until you genuinely need native features, because native queries are coupled to your database.
@Query(value = "SELECT * FROM posts " +
"WHERE MATCH(title, body) AGAINST (:term)",
nativeQuery = true)
List<Post> search(@Param("term") String term);
Performance first
Projections with constructor expressions avoid loading whole entities: SELECT new com.example.PostSummary(p.id, p.title) FROM Post p. Use them for lists where callers need only a few fields, and let Hibernate write SQL you can inspect in the logs.
Key Points
- JPQL queries entities, keeping schema details hidden.
- Always bind parameters; never concatenate input into queries.
- Native queries unlock database-specific SQL, at the cost of portability.
- Use constructor projections to avoid fetching full entities.
- Inspect generated SQL when performance matters.