Jump into concepts and practice - no test required
or
Recommended
Test this pattern10 questions across easy, medium, and hard to know if this pattern is strong
Using @Query for Custom JPQL in Spring Boot
📖 Scenario: You are building a simple Spring Boot application to manage a list of books in a library. You want to find books by their author's name using a custom JPQL query.
🎯 Goal: Create a Spring Data JPA repository with a custom JPQL query using the @Query annotation to find books by author name.
📋 What You'll Learn
Create an entity class Book with fields id, title, and author.
Create a repository interface BookRepository that extends JpaRepository.
Add a custom method findBooksByAuthorName in BookRepository using @Query with JPQL.
Use the custom query to find all books by a given author.
💡 Why This Matters
🌍 Real World
Custom JPQL queries let you write precise database queries in Spring Boot applications, useful when default query methods are not enough.
💼 Career
Understanding @Query with JPQL is essential for backend developers working with Spring Data JPA to efficiently retrieve data from databases.
Progress0 / 4 steps
1
Create the Book entity
Create a class called Book annotated with @Entity. Add private fields Long id annotated with @Id and @GeneratedValue, String title, and String author. Include public getters and setters.
Spring Boot
Hint
Use @Entity on the class. Use @Id and @GeneratedValue on the id field.
2
Create the BookRepository interface
Create an interface called BookRepository that extends JpaRepository<Book, Long>. This interface will be used to access the database.
Spring Boot
Hint
Use public interface BookRepository extends JpaRepository<Book, Long>.
3
Add custom JPQL query method
Inside BookRepository, add a method List<Book> findBooksByAuthorName(String authorName) annotated with @Query. Use JPQL: "SELECT b FROM Book b WHERE b.author = :authorName".
Spring Boot
Hint
Use @Query with JPQL string and @Param for the parameter.
4
Use the custom query method in a service
Create a class BookService with a private final BookRepository field. Add a constructor to inject BookRepository. Add a method List<Book> getBooksByAuthor(String authorName) that calls bookRepository.findBooksByAuthorName(authorName) and returns the result.
Spring Boot
Hint
Use constructor injection for BookRepository and call the custom query method inside getBooksByAuthor.
Practice
(1/5)
1. What is the main purpose of using @Query annotation in Spring Data JPA?
easy
A. To write custom JPQL or SQL queries when default methods are insufficient
B. To automatically generate database tables
C. To configure database connection properties
D. To define entity relationships
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 A
Quick 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
A. @Query("SELECT u FROM User u WHERE u.name = :name") List<User> findByName(@Param("name") String name);
B. @Query(SELECT * FROM User WHERE name = :name) List<User> findByName(String name);
C. @Query("SELECT * FROM User WHERE name = ?1") List<User> findByName(String name);
D. @Query("FROM User WHERE name = ?") List<User> findByName(@Param("name") String name);
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 A
Quick 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:
@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
A. A list of User entities with age less than 30
B. A list of User entities with age equal to 30
C. A list of User entities with age greater than 30
D. A runtime error due to missing parameter
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 C
Quick 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
A. JPQL query uses wrong entity name
B. Missing @Param annotation for the email parameter
C. Return type should be User, not List<User>
D. Query should use native SQL syntax
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 B
Quick 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
A. @Query("SELECT u FROM User u WHERE u.name LIKE :namePart") List<User> findByNameLike(@Param("namePart") String namePart);
B. @Query("SELECT u FROM User u WHERE u.name LIKE '%:namePart%'") List<User> findByNameContains(@Param("namePart") String namePart);
C. @Query("SELECT u FROM User u WHERE u.name = :namePart") List<User> findByNameExact(@Param("namePart") String namePart);
D. @Query("SELECT u FROM User u WHERE LOWER(u.name) LIKE LOWER(CONCAT('%', :namePart, '%'))") List<User> findByNameContainsIgnoreCase(@Param("namePart") String namePart);
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 D