The @Query annotation lets you write your own database queries in Java code. It helps when you want to get data in a special way that the usual methods can't do.
@Query for custom JPQL in Spring Boot
Start learning this pattern below
Jump into concepts and practice - no test required
or
Test this pattern10 questions across easy, medium, and hard to know if this pattern is strong
Introduction
Syntax
Spring Boot
@Query("JPQL query here")
ReturnType methodName(Parameters);JPQL is like SQL but works with Java entity names and fields, not table names.
Place
@Query above repository interface methods.Examples
Spring Boot
@Query("SELECT u FROM User u WHERE u.email = ?1")
User findByEmail(String email);Spring Boot
@Query("SELECT u FROM User u WHERE u.age > :age") List<User> findUsersOlderThan(@Param("age") int age);
@Modifying.Spring Boot
@Query("UPDATE User u SET u.status = 'ACTIVE' WHERE u.lastLogin < :date") @Modifying int activateOldUsers(@Param("date") LocalDate date);
Sample Program
This example shows a repository method using @Query to find users older than a given age. It uses a named parameter :age and returns a list of users.
Spring Boot
import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.query.Param; import org.springframework.stereotype.Repository; import java.util.List; @Entity public class User { @Id private Long id; private String name; private String email; private int age; // getters and setters } @Repository public interface UserRepository extends JpaRepository<User, Long> { @Query("SELECT u FROM User u WHERE u.age > :age") List<User> findUsersOlderThan(@Param("age") int age); } // In a service or test class: // List<User> users = userRepository.findUsersOlderThan(30); // This returns all users older than 30 years.
Important Notes
Always use entity names and field names in JPQL, not database table or column names.
For update or delete queries, add @Modifying annotation and run inside a transaction.
Use @Param to name parameters clearly and avoid confusion.
Summary
@Query lets you write custom JPQL queries in Spring Data repositories.
Use it when method names can't express the query you want.
Remember to use entity names and parameters properly for clear and working queries.
Practice
1. What is the main purpose of using
@Query annotation in Spring Data JPA?easy
Solution
Step 1: Understand default query methods
Spring Data JPA provides default query methods like findById, but they are limited.Step 2: Role of @Query
@Query allows writing custom JPQL or SQL queries to handle complex or specific data retrieval needs.Final Answer:
To write custom JPQL or SQL queries when default methods are insufficient -> Option AQuick Check:
@Query purpose = custom queries [OK]
Hint: Remember @Query is for custom queries beyond defaults [OK]
Common Mistakes:
- Thinking @Query creates tables
- Confusing @Query with database config
- Assuming @Query defines entity relations
2. Which of the following is the correct syntax to define a custom JPQL query using
@Query in a Spring Data JPA repository interface?easy
Solution
Step 1: Check JPQL syntax
JPQL uses entity names and fields, not table names or * syntax.Step 2: Parameter binding
Named parameters use :paramName and must be linked with @Param("paramName") in method.Final Answer:
@Query("SELECT u FROM User u WHERE u.name = :name") List<User> findByName(@Param("name") String name); -> Option AQuick Check:
JPQL + named param + @Param = correct syntax [OK]
Hint: Use entity names and :param with @Param for correct JPQL [OK]
Common Mistakes:
- Using SQL syntax (*) instead of JPQL
- Missing @Param annotation for named parameters
- Using positional parameters incorrectly
3. Given the repository method:
What will be the result of calling
@Query("SELECT u FROM User u WHERE u.age > :minAge")
List<User> findUsersOlderThan(@Param("minAge") int minAge);What will be the result of calling
findUsersOlderThan(30)?medium
Solution
Step 1: Analyze the JPQL query
The query selects users where age is greater than the parameter minAge.Step 2: Understand method call
Calling findUsersOlderThan(30) sets minAge to 30, so users older than 30 are returned.Final Answer:
A list of User entities with age greater than 30 -> Option CQuick Check:
minAge=30, query > minAge = users older than 30 [OK]
Hint: Check parameter value and query condition carefully [OK]
Common Mistakes:
- Confusing > with >= or =
- Assuming parameter is ignored
- Expecting users younger than 30
4. Identify the error in the following repository method:
@Query("SELECT u FROM User u WHERE u.email = :email")
List<User> findByEmail(String email);medium
Solution
Step 1: Check parameter binding
The query uses a named parameter :email, so the method parameter must have @Param("email") annotation.Step 2: Validate other parts
Entity name User is correct, return type List<User> is valid, and JPQL syntax is correct.Final Answer:
Missing @Param annotation for the email parameter -> Option BQuick Check:
Named param requires @Param annotation [OK]
Hint: Always add @Param for named parameters in @Query [OK]
Common Mistakes:
- Omitting @Param causes runtime errors
- Confusing JPQL with native SQL
- Assuming return type must be single entity
5. You want to write a custom JPQL query using
@Query to find all users whose name contains a given substring (case insensitive). Which of the following method definitions correctly achieves this?hard
Solution
Step 1: Understand case insensitive search
Use LOWER() on both field and parameter to ignore case.Step 2: Use LIKE with wildcards
Concatenate '%' before and after parameter to find substring matches.Step 3: Check parameter binding
Named parameter :namePart is linked with @Param("namePart") correctly.Final Answer:
@Query("SELECT u FROM User u WHERE LOWER(u.name) LIKE LOWER(CONCAT('%', :namePart, '%'))") List<User> findByNameContainsIgnoreCase(@Param("namePart") String namePart); -> Option DQuick Check:
LOWER + LIKE + CONCAT + @Param = correct case-insensitive contains [OK]
Hint: Use LOWER() and CONCAT('%', param, '%') for case-insensitive contains [OK]
Common Mistakes:
- Using LIKE with parameter inside quotes disables binding
- Not using LOWER() for case insensitivity
- Using = instead of LIKE for substring search
