@Query Annotation
Intermediate@Query overrides the derived query with explicit JPQL or native SQL; use @Modifying with @Transactional for bulk UPDATE or DELETE repository methods.
Overview
@Query lets you write explicit JPQL or native SQL on a Spring Data repository method, bypassing method name derivation. It is the preferred choice when the query is too complex for a readable method name. Named parameters (:param) are bound via @Param. For INSERT/UPDATE/DELETE bulk operations, combine @Query with @Modifying and @Transactional — without @Modifying, Spring Data raises an exception; without @Transactional, the modifying query runs outside a transaction. @Modifying's clearAutomatically=true clears the persistence context after the bulk update to prevent stale entities.
JPQL @Query
Use JPQL @Query for portable queries that benefit from entity-level aliases and relationship traversal without writing table-specific SQL.
public interface OrderRepository extends JpaRepository<Order, Long> {
// JPQL — entity alias, relationship traversal
@Query("SELECT o FROM Order o JOIN FETCH o.items WHERE o.customerId = :cid AND o.status = :status")
List<Order> findWithItemsByCustomer(@Param("cid") Long customerId,
@Param("status") String status);
// Projection with JPQL constructor expression
@Query("SELECT new com.example.dto.OrderSummary(o.id, o.status, o.totalAmount) " +
"FROM Order o WHERE o.createdAt >= :since")
List<OrderSummary> findSummariesSince(@Param("since") LocalDateTime since);
// Positional parameters (less readable but shorter)
@Query("SELECT o FROM Order o WHERE o.status = ?1 ORDER BY o.createdAt DESC")
List<Order> findByStatus(String status);
}@Modifying — Bulk UPDATE and DELETE
@Modifying marks the @Query as a DML statement (INSERT/UPDATE/DELETE). @Transactional is required — add it to the repository method or ensure a transaction is provided by the caller.
public interface OrderRepository extends JpaRepository<Order, Long> {
// Bulk UPDATE — requires @Modifying + @Transactional
@Modifying(clearAutomatically = true) // clear L1 cache after bulk update
@Transactional
@Query("UPDATE Order o SET o.status = :newStatus WHERE o.status = :oldStatus AND o.createdAt < :cutoff")
int bulkUpdateStatus(@Param("newStatus") String newStatus,
@Param("oldStatus") String oldStatus,
@Param("cutoff") LocalDateTime cutoff);
// Bulk DELETE
@Modifying
@Transactional
@Query("DELETE FROM Order o WHERE o.status = 'CANCELLED' AND o.createdAt < :cutoff")
int deleteOldCancelledOrders(@Param("cutoff") LocalDateTime cutoff);
}flushAutomatically and clearAutomatically
clearAutomatically=true clears the first-level cache after the bulk DML so subsequent queries see the updated DB state. flushAutomatically=true flushes pending entity changes before the DML executes.
@Modifying(
flushAutomatically = true, // flush dirty entities BEFORE bulk update
clearAutomatically = true // clear L1 cache AFTER bulk update
)
@Transactional
@Query("UPDATE Order o SET o.priority = :p WHERE o.customerId = :cid")
int setPriority(@Param("p") int priority, @Param("cid") Long customerId);
// Without clearAutomatically=true:
// 1. Bulk UPDATE runs → DB rows updated
// 2. em.find(Order, id) returns stale entity from L1 cache — BUG
// With clearAutomatically=true:
// 2. L1 cache cleared → next em.find() hits DB → fresh dataKey Points to Remember
- 1@Query accepts JPQL (default) or SQL (nativeQuery=true) inline on the repository method
- 2Use @Param to bind named parameters; positional ?1 also works but is less readable
- 3@Modifying is required for UPDATE/DELETE @Query methods — omitting it throws an exception
- 4@Transactional must be present on the method or the calling service for @Modifying queries
- 5clearAutomatically=true clears the L1 cache after bulk DML — prevents reading stale entities
- 6JPQL constructor expression: SELECT new com.example.Dto(a, b) FROM Entity — maps to DTO constructor
Interview Questions
Sign in to ask AriaWhat happens if you add @Modifying without @Transactional?
Why is clearAutomatically=true important after a bulk update?
What is the JPQL constructor expression and when do you use it?
What is the difference between @Query JPQL and nativeQuery=true?
How does flushAutomatically differ from clearAutomatically?
Ask Aria about @Query Annotation
Your personal AI tutor — ask anything about this concept
Revision Status
Personal Notes
Sign in to save personal notes for this topic.
Discussion
Sign in to join the discussion.