JPQL(Java Persistence Query Language)
: Entity 객체를 조회하는 쿼리
QueryDSL
:
쿼리 메소드
: 쿼리메소드의 경우 조건이 많아지게 되면 메소드의 이름이 길어지는 단점이 있다.
public interface BookRepository extends JpaRepository<Book ,Long> {
List<Book> findByCategoryIsNullAndNameEqualsAndCreatedAtGreaterThanEqualAndUpdatedAtGreaterThanEqual(String name, LocalDateTime createdAt, LocalDateTime updatedAt);
}
!!! @Query 어노테이션을 사용하여 메소드 명을 줄이고 가독성을 높인다.
@Query 어노테이션 사용하기
: @Query는 Cutsom 쿼리로 구체적으로 작성하기 위한 어노테이션
@Query 정의
- @Query(value= )의 값은 SQL 쿼리문이 아닌 JPQL 쿼리문을 사용
- JPA 엔티티 기반으로 쿼리 생성하여 테이블 명이 아닌 엔티티명으로 쿼리문을 작성
쿼리 파라미터 사용
- JPQL 엔티티를 바라봄, 동적으로 변경되는 파라미터가 ?숫자(메소드의 파라미터 순서)와 맵핑
- @Param을 사용하여 명시해주어 :변수명으로 맵핑
/*
* @Query(value = "select b from Book b " +
* "where name = ?1 " +
* "and createdAt >= ?2 " +
* "and updatedAt >= ?3")
*/
@Query(value = "select b from Book b " +
"where name = :name " +
"and createdAt >= :createdAt " +
"and updatedAt >= :updatedAt and category is null")
List<Book> findByNameRecently(
@Param("name") String name,
@Param("createdAt") LocalDateTime createdAt,
@Param("updatedAt") LocalDateTime updatedAt);
튜플로 특정 컬럼 값 추출
BookRepository.java
@Query(value = "select b.name as name" +
", b.category as category " +
"from Book b")
List<Tuple> findBookNameAndCategoryTuple();
/* @Query(value = "select b.name as name" +
", b.category as category " +
"from Book b")
List<BookNameAndCategory> findBookNameAndCategoryEntity();*/
Test.java
// tuple
bookRepository.findBookNameAndCategoryTuple().forEach(tuple -> {System.out.println(tuple.get(0) + " : "+tuple.get(1));});
// tuple -> Entity Convert Error
//bookRepository.findBookNameAndCategoryEntity().forEach(B -> {System.out.println(B.getName() + " : "+B.getCategory());});
추출 대상이 두개이상이므로 튜플타입으로 추출 가능하다.
두개의 컬럼 값을 호출하는 메소드에서 쿼리에서 튜플형식의 맵 객체를 받아 BooknameAndCategory 타입으로 컨버팅이 불가하다는 에러 발생.
그에 따라 tuple로 변경하여 사용하되, 언제까지나 tuple로 사용하여 get 메소드로 컬럼값을 가져올 수 없다.
그래서 DTO 인터페이스나 클래스 방식으로 값을 추출하면 된다.
DTO 인터페이스/클래스로 특정 컬럼 값 추출
Class/Interface
@Data
@AllArgsConstructor
@NoArgsConstructor
public class BookNameAndCategory {
private String name;
private String category;
}
public interface BookNameAndCategory {
String getName();
String getCategory();
}
BookRepository.java
/** 클래스 DTO 형식
* 문자열이라 풀패키지명
* */
@Query(value = "select new com.test.jpa.jpaProj.repository.dto.BookNameAndCategory(b.name" +
", b.category) " +
"from Book b")
List<BookNameAndCategory> findBookNameAndCategory();
/** 페이징 쿼리메소드*/
@Query(value = "select new com.test.jpa.jpaProj.repository.dto.BookNameAndCategory(b.name" +
", b.category) " +
"from Book b")
Page<BookNameAndCategory> findBookNameAndCategory(Pageable pageable);
Test.java
// interface BookNameAndCategory DTO
bookRepository.findBookNameAndCategory().forEach(b -> {System.out.println(b.getName() + " : "+b.getCategory());});
// class BookNameAndCategory DTO
bookRepository.findBookNameAndCategory().forEach(b -> {System.out.println(b.getName() + " : "+b.getCategory());});
// Paging
//bookRepository.findBookNameAndCategory(PageRequest.of(0,1));
bookRepository.findBookNameAndCategory(PageRequest.of(0,1)).forEach(
bookNameAndCategory -> System.out.println(bookNameAndCategory.getName()+" : "+bookNameAndCategory.getCategory()));
bookRepository.findBookNameAndCategory(PageRequest.of(1,1)).forEach(
bookNameAndCategory -> System.out.println(bookNameAndCategory.getName()+" : "+bookNameAndCategory.getCategory()));
Native Query 사용
Native 사용 이유
- JPA 사용하는 불필요한 쿼리를 없애고 네이티브 쿼리를 사용함으로써 성능향상
- JPA에서 지원하지 않는 기능을 사용해야 할 경우
예시
BookRepository.java
/*
* native query 사용
* : JPQL과 다르게 엔티티 속성을 사용하지 못하고 테이블을 사용
* value값이 DB에서 그대로 실행하여, 엔티티에서 설정한 어노테이션이 안먹힘
*/
@Query(value = "select * from book",nativeQuery = true)
List<Book> findAllCustom();
// JPA에서 deleteAll(), deleteAllInbatch()
// deleteAll의 경우 id로 하나씩 select 하여 delete 로 인한 성능 저하를 가져오므르 native query가 필요
// update의 경우 AllInBatch가 없음
// @Modifying : DML작업의 경우 리턴값을 받도록 적용
// @Transactional : 트랜잭션이 필요한 경우 적용
@Transactional
@Modifying
@Query(value = "update book set category ='it전문서'",nativeQuery = true)
int updateCategory();
: nativeQuery = true 옵션값을 적용하여 Entity가 아닌 Table을 가리킴. Field가 아닌 Column명을 사용.
'Spring > 1-3. JPA' 카테고리의 다른 글
낙관적 락(Optimistic Lock) 과 비관적 락(Pessimistic Lock) (0) | 2024.11.13 |
---|---|
(8. Spring Data JPA) 영속성 전이 Cascade (0) | 2023.05.11 |
(7. Spring Data JPA) Transaction Manager (0) | 2023.05.10 |
(6. Spring Data JPA) 영속성 컨텍스트 Persistence Context (0) | 2023.05.06 |
(5. Spring Data JPA) Entity Listener 활용 (1) | 2022.10.18 |