Spring Data @Query

The `@Query` annotation lets a Spring Data repository method use an explicitly defined JPQL or native SQL query. It is useful when a derived query method is insufficient or when the query needs precise control.

`@Query` is placed on a repository method to define the query that Spring Data should execute when that method is called. For JPA repositories, the query is normally JPQL, which refers to entity classes and their fields rather than database tables and columns.

A JPQL query can use named parameters such as `:email`. The corresponding method parameter is commonly annotated with `@Param("email")`, making the mapping between the method argument and query parameter explicit.

When database-specific SQL is required, `@Query` can be used with `nativeQuery = true`. In that case, the query is SQL and uses the actual database table and column names rather than JPQL entity and property names.

`@Query` is commonly used for custom reads and writes. For modifying operations such as `UPDATE` or `DELETE`, the repository method generally also needs `@Modifying`, and the operation must execute within an appropriate transaction.

The main tradeoff is explicit control versus portability and maintainability. JPQL stays closer to the JPA entity model, while native SQL can access database-specific features but couples the repository more closely to the database schema and SQL dialect.

Key points

Interview questions

What is `@Query` in Spring Data JPA?

`@Query` lets you define the query executed by a repository method instead of relying on query derivation from the method name. For JPA repositories, the query is normally written in JPQL. It is useful when a derived method becomes too complex or cannot express the required query. The annotation can also be configured to execute native SQL.

What is the difference between JPQL and native queries with `@Query`?

JPQL operates on the JPA domain model, so it uses entity names and entity properties. Native queries use SQL understood by the database and therefore reference tables and columns. Native queries can expose database-specific capabilities but increase coupling to the database schema and dialect. You select native SQL by setting `nativeQuery = true`.

How do you pass parameters to an `@Query` method?

A query can declare a named parameter such as `:email`. The repository method can associate its argument with that parameter using `@Param("email")`. The names need to correspond so Spring Data can bind the argument correctly. Positional parameters are another option, but named parameters are often easier to read.

What is `@Modifying` used for with `@Query`?

`@Modifying` is used when a repository query changes data rather than simply selecting it. Typical examples are JPQL `UPDATE` and `DELETE` statements. It is commonly combined with `@Query` on the repository method. Transaction management is also important because the modification needs to execute within an appropriate transactional context.

When would you choose `@Query` instead of a derived query method?

I would use `@Query` when the required query is awkward or impossible to express clearly through a method name. It can make complex joins, projections, filtering, or modifying statements explicit. I would still prefer a derived method for simple conditions because it avoids embedding query text in the repository. The choice should consider readability, maintainability, and whether database-specific SQL is actually needed.