Foundation · Build

@Query and JPQL

@Query writes JPQL against your entity model, or native SQL against tables when a vendor feature earns its portability cost.

Primary source: Spring Data JPA: Declaring JPQL and Native Queries

20 min

Lesson 7 of 17

1d streak

The Architectural Question

JPQL targets entities and fields; pasting table SQL into it fails at startup with a validation error rather than at first execution.

What this guide proves

  • @Query
  • JPQL
  • Native SQL

JPQL vs Native SQL: Abstraction vs Database Power

Architectural Boundary · Do Not Confuse

Concept A

JPQL (@Query("SELECT o FROM Order o..."))

Concept B

Native SQL (@Query(value = "...", nativeQuery = true))

JPQL operates on entity classes and their Java attributes (SELECT o FROM OrderEntity o WHERE o.customerEmail = :email). It is portable across databases and automatically maps to managed entities. Native SQL executes raw database syntax, unlocking database-specific functions (e.g., PostgreSQL JSONB operators, window functions, CTEs) but bypassing entity mappings.

High-performance read queries with JPQL constructor expressions

Loading full entities when you only need 3 fields wastes memory and CPU. JPQL constructor expressions instantiate read-only DTO records directly in the database query.

OrderRepository.java
@Query("""
    SELECT new com.example.orders.dto.OrderSummaryDto(o.id, o.status, o.totalAmount)
    FROM OrderEntity o
    WHERE o.customerId = :customerId
""")
List<OrderSummaryDto> findSummariesByCustomerId(@Param("customerId") UUID customerId);

Active Recall Checkpoint

What annotation must you add to a @Query method that performs an UPDATE or DELETE statement?

Hint: Spring Data requires an annotation to signal data mutation.

Show answer & explanation

@Modifying. Without @Modifying, Spring Data expects the query to be a SELECT statement and throws an InvalidDataAccessApiUsageException.

Query selection guidelines

Use it when

Use JPQL constructor expressions for read-heavy operations and reports to bypass dirty checking overhead.

Reconsider when

Use nativeQuery = true only when utilizing database-specific extensions (e.g., PostgreSQL tsvector full-text search, JSONB functions).

Synthesis & Production Verification

Deliberate Failure Condition

  1. Break: Write "SELECT * FROM orders" inside @Query without nativeQuery = true
  2. Observe: IllegalArgumentException: query validation failed at startup
  3. Repair: JPQL parses against the entity metamodel; set nativeQuery = true only for genuinely database-specific SQL.

Production Acceptance Criteria

  • Write a JPQL @Query bound with @Param parameters
  • JOIN FETCH an association in one round-trip
  • Rewrite one query as native SQL and justify the trade-off

Architectural & Technical Review

Core Interview Questions

Q01How does JPQL differ from native SQL in Spring Data?Show answer

JPQL queries entity classes and Java properties portably; native SQL runs raw database syntax directly against database tables.

Q02What is the performance advantage of JPQL constructor expressions?Show answer

They instantiate read-only DTO records directly from the database result set without attaching managed entities to the Persistence Context.

Q03What annotation is required for UPDATE or DELETE statements in @Query?Show answer

@Modifying must be added to tell Spring Data to execute an executeUpdate() rather than an executeQuery().

Production Pitfalls

Critical Anti-Patterns

  • Pitfall: Modifying entities in bulk without clearing the Persistence Context — @Modifying queries update the database directly, bypassing the L1 cache; set clearAutomatically = true to prevent stale reads.
  • Pitfall: Using string concatenation in queries instead of parameters — Concatenating parameters directly into query strings introduces severe SQL injection vulnerabilities.

Primary Documentation & Specifications