Use Case #1 : JPQL, Parameter mappingUse case #2 : @Query 결과를 interface 혹은 구체클래스에 매핑Native Query @Query(nativeQuery=true)QueryDSL참고
- queryMethod의 커스텀 버전
- queryMethod의 가독성 문제
- 함수이름이 되게 길어지는 문제
- Entity에서 전체가 아닌 필요한 필드들만 추출해서 조회가 가능함
- nativeQuery를 쓰게 되면 QueryDSL을 주로 사용함
Use Case #1 : JPQL, Parameter mapping
public interface BookRepository extends JpaRepository<Book, Long>{ List<Book> findByCategoryIsNullAndNameEqualsAndCreatedAtGreaterThanEqualAndUpdatedAtGreaterThanEqual( 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); }
- @Query의 value 안에 들어있는 쿼리를 JPQL이라고 함. JPA의 Entity를 기반으로 하는 쿼리
- Book, createdAt, updatedAt 등, Entity 안에서 정의된 변수 이름임
- 쿼리메소드로 만드는 쿼리와 비슷한 과정을 통해서 쿼리가 만들어짐(JPQL)
- JPQL 안에 파라미터를 넣는 방법
- ?1, ?2 와 같이 순서대로 매핑하는 방법
- 그러나 순서에 의한 파라미터 넘김은 자바에서 지양하고 있다고 함 ← 언제 파라미터가 추가될지 모르니까
- @Param을 이용한 파라미터 연결
Use case #2 : @Query 결과를 interface 혹은 구체클래스에 매핑
@Query(value="select b.name as name, b.category as category from Book b") List<BookNameAndCategory> findBookNameAndCategory(); public interface BookNameAndCategory { String getName(); String getCategory(); } //test code bookRepository.findBookNameAndCategory().forEach( b -> System.out.println(b.getName() + " : " + b.getCategory()));
@Query(value="select new com.example.bookmanager.repository.dto.BookNameAndCategory(b.name, b.category) from Book b") List<BookNameAndCategory> findBookNameAndCategory(); @Data @NoArgsConstructor @AllArgsConstructor public class BookNameAndCategory { private String name; private String category; }
Native Query @Query(nativeQuery=true)
- JPQL 처럼 Entity를 이용하지 못함. 실제 raw query임
- dialect를 활용하지 않기에 특정 db에 맞게 쿼리 작성 해야함 → 최소한으로 사용하는 것이 좋음
- 사용 이유?
- 성능에 대한 이슈 : JpaRepository를 활용한 update는 항상 search후 save를 통해 merge로 업데이트 됨
List<Book> books = bookRepository.findAll(); for(Book book : books){ book.setCategory("IT전문서"); } bookRepository.saveAll(books); // 대량 데이터에 대해 update 시 성능 저하. id 값으로 하나씩 update 해야하기에 // -> 이럴 때 native query사용 @Transactional @Modifying @Query(value = "update book set category = 'IT전문서'", nativeQuery = true) int updateCategory();
@Modifying
- 그러나 항상 붙이는게 좋은 것만은 아님. 왜냐하면 업데이트를 조회랑 같이 사용하는게 아닌 따로 사용한다면 굳이 persistence context를 비워주는 작업을 할 필요가 없는 것임
javax.persistence.TransactionRequiredException: Executing an update/delete query
Native Query 이용시 dto projection 방법
@SqlResultSetMapping과 @NamedNativeQuery 이용