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
Lesson 7 of 17
1d streakThe 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
JPQL (@Query("SELECT o FROM Order o..."))
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.
@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
- Break: Write "SELECT * FROM orders" inside @Query without nativeQuery = true
- Observe: IllegalArgumentException: query validation failed at startup
- 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
Key Takeaway
JPQL operates on entity classes and object graphs portably; use constructor expressions for high-performance read-only projections.
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
Lesson Primary References
Supplementary Module Resources