What is the @Query annotation in Spring Data JPA, and how do you bind parameters to a JPQL query?
answer
- JPQL = entity + field names, not tables/columns
- :name + @Param vs ?1 positional (1-based)
- named params refactor-safe & self-documenting
- JPQL validated at startup, native is not
- 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 linespublic 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
Must know @Query overrides the method-name query, defaults to JPQL, and how :name/@Param binding works.
Should articulate JPQL-vs-SQL (fields vs columns) and startup validation of named JPQL.
Should discuss when to prefer @Query over derived queries and projection options.
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