Skip to main content
PreparationZone Logo
PrepZone

Native Queries, Criteria API, and Specifications

Native SQL, the Criteria builder's verbosity, and Specification composition for optional filters.

Pass checkpoint below

Why this matters

  • BookStore search screens send genre, price, author, and keyword in every combination. A derived method per combination does not scale.
  • Interviewers ask for the Criteria API, then ask why teams dislike it. The useful answer names the verbosity problem and Specifications as the fix.
  • Native SQL still belongs in the toolbox for reports PostgreSQL can express and JPQL cannot.

Three query styles

L1 · Fresher

Derived methods for simple finds, @Query for fixed JPQL or SQL, Criteria or Specification when the WHERE clause depends on the request.

Criteria API

L2 · Intermediate

CriteriaBuilder creates a CriteriaQuery, a Root, and Predicates. It is type-oriented Java, not a query string.

Specification

L3 · Advanced

Specification<Book> is one toPredicate method. You and and or them in the service and pass the result to JpaSpecificationExecutor.

Native SQL boundary

L4 · Expert

Use nativeQuery = true for window functions, ILIKE, and vendor types. You lose entity-graph portability and must maintain the count query for pagination.

Native queries

JPQL does not speak every PostgreSQL feature. Native queries use table and column names:

Java
// learn:fragment
public interface BookRepository extends JpaRepository<Book, Long> {

    @Query(value = """
        SELECT id, title, price
        FROM books
        WHERE genre = :genre
          AND title ILIKE '%' || :keyword || '%'
        ORDER BY price DESC
        """,
        countQuery = """
        SELECT count(*)
        FROM books
        WHERE genre = :genre
          AND title ILIKE '%' || :keyword || '%'
        """,
        nativeQuery = true)
    Page<BookSummaryView> search(
        @Param("genre") String genre,
        @Param("keyword") String keyword,
        Pageable pageable);
}

Native query rules

  • Table names, not entity names — books, not Book, unless the table is named Book.
  • Pagination needs countQuery — Spring cannot reliably rewrite native SQL into a count.
  • Projections — Return an interface or a DTO constructor. Returning a raw Object[] spreads column indexes through the service.
  • SQL injection — Keep using :keyword parameters. Never concatenate user input into the query string.

The rest of this guide is part of Pro

Free covers every fresher guide in full. Pro unlocks Senior, Staff and Architect guides across every track.

Still to come · 3 sections

  • Criteria API
  • Specification API
  • Fetch joins inside a Specification

Test yourself

Answer these before moving on — recall is what makes it stick.