쿼리메서드는 아래의 코드와 같이 조건이 많아지게 된다면 method의 이름이 어마어마하게 길어지게 된다.
public interface BookRepository extends JpaRepository<Book, Long> {
List<Book> findByCategoryIsNullAndDeletedFalse();
}
이러한 문제는 @Qeury를 사용하면 메서드 명을 줄일 수 있고 더욱 더 가독성 있는 메서드를 만들 수 있다.
@Query(value = "select b from Book b " +
"where name =?1 and createdAt >=?2 and updatedAt >= ?3 and category is null")
List<Book> findByNameRecently(String name, LocalDateTime createdAt, LocalDateTime updatedAt);
@Query(value = "select b from Book b " +
"where name =?1 and createdAt >=?2 and updatedAt >= ?3 and category is null")
List<Book> findByNameRecently(String name, LocalDateTime createdAt, LocalDateTime updatedAt);
@Query(value = "select b from Book b " +
"where name = :name and createdAt >= :createdAt and updatedAt >= :updatedAt and category is null")
List<Book> findByNameRecently2(
@Param("name") String name,
@Param("createdAt") LocalDateTime createdAt,
@Param("updatedAt") LocalDateTime updatedAt);
위와 같이 메서드의 파라미터들을 @Param을 통해 이름을 정해주고 where문에서는 :name, ?createdAt과 같이 넣어주는 방법이다.
해당 방법은 parameter순서에 영향을 받지 않기 때문에 logic의 변경에 더 자유롭고 부작용에서 더 자유로워질 수 있다.
public interface BookRepository extends JpaRepository<Book, Long> {
@Query(value = "select b.name as name, b.category as category from Book b")
List<BookNameAndCategory> findBookNameAndCategory();
}
// BookNameAndCategory.java
public interface BookNameAndCategory {
String getName();
String getCategory();
}
interface를 선언해주고 위와 같이 사용을 하면 getName, getCategory와 같은 메서드를 통해 해당 column의 값만 가져올 수 있다.
public interface BookRepository extends JpaRepository<Book, Long> {
@Query(value = "select new com.example.jpa_study.repository.dto.BookNameAndCategory(b.name, b.category) from Book b")
List<BookNameAndCategory> findBookNameAndCategory();
}
// BookNameAndCategory.java
@Data
@AllArgsConstructor
@NoArgsConstructor
public class BookNameAndCategory {
private String name;
private String category;
}
Class를 통해 받는 방법도 interface와 유사하며 똑같이 getName, getCategory와 같은 메서드를 통해 해당 column의 값만 가져올 수 있다.
하지만 class를 통해 필요한 값만 가져오려면 해당 class의 위치를 정확하게 대입해줘야한다는 점을 주의해줘야한다❗❗
native query는 DB에서 사용하는 SQL문을 그대로 사용하게 해준다.
@Query(value = "select * from book", nativeQuery = true)
List<Book> findAllCustom();
@Query(value = "show tables", nativeQuery = true)
List<String> showTables();
@Transactional
이 붙어있지만 native query는 데이터 조작을 할 때는 직접 붙여줘야한다.@Modyfying
이라는 것을 붙여 update가 되었다는 것을 확인시켜줘야 return값을 받을 수 있다. @Transactional
@Modifying
@Query(value = "update book set category = 'IT Book'", nativeQuery = true)
int updateCategories(); // return 타입을 int, long과 같은 타입으로 하면 업데이트 된 row의 수를 return해준다.
🚨 주의할 점
Native Query 특정 DB에 의존성을 가진 쿼리를 만들게 된다.
-> DB종류가 바껴도 DB에 맞게 자동으로 쿼리를 바꿔준다는 JPA의 장점에서 빗겨나가게 된다.