skip to content

@Query JPQL, Native & @Modifying

@Query takes JPQL or, with nativeQuery, raw SQL, with named or positional parameters, and @Modifying is required for update and delete statements. Interviewers press on the stale persistence context that clearAutomatically exists to fix.

part ofSpring Frameworkoverview, primer and where to startread it →
on this pageshow

questions

5

What is the @Query annotation in Spring Data JPA, and how do you bind parameters to a JPQL query?

level: juniorimportance: must knowfreq 78%

answer

  1. JPQL = entity + field names, not tables/columns
  2. :name + @Param vs ?1 positional (1-based)
  3. named params refactor-safe & self-documenting
  4. JPQL validated at startup, native is not
  5. overrides derived method-name query

basics

~20 s

@Query lets you write your own query on a repository method instead of relying on the method name. By default it's JPQL. You bind values with named parameters like :name using @Param, or by position with ?1.

solid answer

~40 s

@Query is a Spring Data JPA annotation placed on a repository method to declare an explicit query, overriding the derived-query mechanism that parses method names. By default the string is JPQL (Java Persistence Query Language) — it references entity classes and fields, not database tables and columns. You bind method arguments two ways: named parameters (:email in the query, matched to a method argument annotated @Param("email")) or positional parameters (?1, ?2 matched by argument order). Named parameters are preferred because they are self-documenting and refactor-safe. Spring parses and validates JPQL against the entity metamodel at startup, so a typo in a field name fails fast rather than at runtime. Use @Query when the derived name would be unreadable or when you need joins, projections, or expressions the naming DSL can't express.

code

java · 14 lines
java
public interface UserRepository extends JpaRepository<User, Long> {

    // JPQL: references the User entity and its emailAddress field
    @Query("SELECT u FROM User u WHERE u.emailAddress = :email")
    Optional<User> findByEmail(@Param("email") String email);

    // Positional binding (1-based ?1, ?2)
    @Query("SELECT u FROM User u WHERE u.status = ?1 AND u.active = ?2")
    List<User> findByStatus(Status status, boolean active);

    // Collection parameter with IN
    @Query("SELECT u FROM User u WHERE u.id IN :ids")
    List<User> findAllByIds(@Param("ids") Collection<Long> ids);
}

go deeper

for a junior

Must know @Query overrides the method-name query, defaults to JPQL, and how :name/@Param binding works.

for a middle

Should articulate JPQL-vs-SQL (fields vs columns) and startup validation of named JPQL.

for a senior

Should discuss when to prefer @Query over derived queries and projection options.

for a principal

Frames @Query as one tool among derived queries, Criteria, and QueryDSL; weighs maintainability and validation trade-offs.

## What @Query is `@Query` is an annotation from `org.springframework.data.jpa.repository.Query`. You put it on a method inside a Spring Data repository interface (one that extends `JpaRepository`, `CrudRepository`, etc.) to supply the exact query text yourself. Without it, Spring Data builds queries by **parsing the method name** — e.g. `findByEmailAndActiveTrue(...)` is translated into a query. That derived-query mechanism breaks down for anything complex (joins, aggregate functions, custom projections), producing method names that are long and unreadable. `@Query` lets you write the query directly and keep a short, clear method name. ## JPQL vs SQL By default the query string is **JPQL** (Java Persistence Query Language), the object-oriented query language defined by the JPA spec. Key distinction: - JPQL operates on **entity names and field names**, not table and column names. Example: `SELECT u FROM User u WHERE u.emailAddress = :email` — `User` is the `@Entity` class, `emailAddress` is a Java field, even if the column is `email_address`. - The JPA provider (Hibernate) translates JPQL into vendor-specific SQL at runtime. ```java @Query("SELECT u FROM User u WHERE u.status = :status") List<User> findByStatus(@Param("status") Status status); ``` ## Parameter binding — two styles **Named parameters** (recommended): a colon-prefixed name in the query (`:status`) matched to a method argument annotated with `@Param("status")`. ```java @Query("SELECT u FROM User u WHERE u.email = :email AND u.active = :active") User find(@Param("email") String email, @Param("active") boolean active); ``` **Positional parameters**: `?1`, `?2`, … bound by the **1-based** order of method arguments (there is no `?0`). ```java @Query("SELECT u FROM User u WHERE u.email = ?1 AND u.active = ?2") User find(String email, boolean active); ``` Named parameters are preferred: they are self-documenting, order-independent, and survive argument reordering during refactoring. Positional parameters are terse but fragile. ### Kotlin / Java 8+ note If you compile with parameter-name metadata (`-parameters` javac flag, on by default in Spring Boot builds), you can sometimes omit `@Param` and Spring matches by argument name. Relying on that is brittle; keep `@Param` explicit. ## Startup validation Spring Data (via Hibernate) parses named JPQL queries at application startup. A misspelled entity or field name throws immediately, so mistakes surface at boot instead of on the first request. (Native SQL, covered separately, is **not** validated this way.) ## Common gotchas - **JPQL uses field names, not column names** — `u.emailAddress`, not `email_address`. Mixing these up is the #1 beginner error. - **`SELECT u` returns the whole entity**; to return specific columns use a constructor expression or a projection. - **Collection parameters** work with `IN`: `WHERE u.id IN :ids` bound to a `Collection<Long>`. - **LIKE with wildcards**: pass the `%` in the argument (`"%" + term + "%"`) or use SpEL / `CONCAT` in the query; a bare `:term` won't add wildcards. ## When to use Reach for `@Query` when: the derived method name would be unreadable; you need explicit joins or fetch joins; you want a projection/DTO; or you need functions the naming DSL can't express. Prefer derived queries for simple single-property lookups.

  • In JPQL, does `u.email` refer to the column name or the entity field name?
    The entity field (Java property) name. JPQL is object-oriented; Hibernate translates the field to its mapped column at runtime. The column could be named differently (e.g. email_address).
  • What happens if you misspell a field name in a JPQL @Query?
    Hibernate fails to parse the query at application startup, throwing an exception during context initialization — so the error is caught at boot, not on first use.
  • Do positional parameters start at ?0 or ?1?
    ?1. JPA positional parameters are 1-based; there is no ?0.

saying these in an interview costs you the question

  • Thinking JPQL uses database table/column names instead of entity/field names
  • Believing positional parameters are 0-based (?0)
  • Claiming @Param is always required even with -parameters compilation
  • Confusing @Query default (JPQL) with SQL

context

open as a page

How do you write a native SQL query with @Query, and what changes compared to JPQL?

level: middleimportance: must knowfreq 70%

basics

~20 s

Set nativeQuery=true on @Query and write real database SQL using table and column names instead of entity fields. It's useful for database-specific features JPQL can't express, but the query is not validated at startup and is less portable.

open as a page

What does @Modifying do, and when do you need clearAutomatically and flushAutomatically?

level: seniorimportance: must knowfreq 68%

basics

~20 s

@Modifying marks a @Query as an UPDATE or DELETE (or INSERT native) rather than a SELECT, so Spring calls executeUpdate() and returns the affected-row count. clearAutomatically clears the persistence context after the query so stale cached entities don't hide the change; flushAutomatically flushes pending changes before it runs.

open as a page

What are the trade-offs between named parameters, positional parameters, and safe binding in @Query, and how do you avoid injection?

level: middleimportance: should knowfreq 55%

basics

~20 s

Named parameters (:name with @Param) are readable and refactor-safe; positional parameters (?1, ?2) are terser but tied to argument order. Both are bound safely by the driver, which prevents injection. Never concatenate user input into the query string.

open as a page

How does the SpEL expression #{#entityName} work in a @Query, and why is it useful?

level: principalimportance: should knowfreq 30%

basics

~20 s

Spring Data lets you embed SpEL in a @Query using #{...}. The built-in #entityName variable resolves to the managed entity's name at runtime, so you can write generic base-repository queries like SELECT e FROM #{#entityName} e that work for any entity subtype.

open as a page