본문 바로가기
강의 정리/스프링 데이터 JPA

2. 쿼리 메소드 기능

by 이석준석이 2021. 1. 10.

쿼리 메소드 기능

  1. 메소드 이름으로 쿼리 생성
  2. 메소드 이름으로 JPA Named Query 호출
  3. '@Query' 어노테이션을 사용해서 리포지토리 인터페이스에 쿼리 직접 정의

1. 메소드 이름으로 쿼리 생성하는 기능

 

조회 : find...By

COUNT : count...By

EXISTS : exists...By

삭제 : delete...By

DISTINCT : findDistinct

LIMIT : findFirst3, findFirst, findTop


2. JPA NamedQuery

 

  • query 문을 잘못 작성하면, 어플리케이션 로딩 시점이 컴파일 에러를 발생시키는 장점이 있다.
  • 엔티티 위에 작성할 수 있다.
@NamedQuery(
        name = "Member.findByUsername",
        query = "select m from Member m where m.username = :username"
)
public class Member {

 


JPA 에서 사용하는 방법

public List<Member> findByUsername(String username) {
    return em.createNamedQuery("Member.findByUsername", Member.class)
            .setParameter("username", username)
            .getResultList();
}

Spring Data JPA 에서 사용하는 방법

@Query(name = "Member.findByUsername")
List<Member> findByUsername(@Param("username") String username);

3. @Query, 리포지토리 메소드에 쿼리 직접 정의하기

 

예시)

@Query("select m from Member m where m.username = :username and m.age = :age")
List<Member> findUser(@Param("username") String username, @Param("age") int age);

 

장점

  • 간략한 메소드 이름
    • 메소드 이름으로 쿼리를 작성하는 기능은 메소드가 너무 길어질 수 있지만, 해당 방법은 메소드 이름은 길어지지 않음
  • 어플리케이션 로딩 시점에 컴파일 에러를 제공한다.

4. @Query 로 값, DTO 조회하기

 

값 조회

@Query("select m.username from Member m")
List<String> findUsernameList();

DTO 조회

  • DTO 를 생성한 뒤, 생성자로 객체를 생성하는 것 처럼 하여 사용
@Query("select new study.datajpa.dto.MemberDto(m.id, m.username, t.name) from Member m join m.team t")
List<MemberDto> findMemberDto();

5. 컬렉션 파라미터 바인딩

 

In 절을 통해서 하는 예제

@Query("select m from Member m where m.username in :names")
List<Member> findbyNames(@Param("names") Collection<String> names);

 


6. 반환 타입

 

반환 타입들

  • List<T>
    • 결과가 없다면 empty List 가 보장됨. (null이 아닌 empty list)
  • T
    • 결과가 없다면 null 이 반환됨
  • Optional<T>
    • 결과가 없으면 optional.empty 반환됨

7. 페이징

 

JPA

  • 직접 만든 setFirstResult, setMaxResults 를 이용한 paging query
  • 직접 만든 count query 

Spring Data JPA

파라미터 기능
Sort 정렬조건
Pageable 페이징 기능 (Sort 가 포함되어있다.)

PageRequest.of 로 생성 가능

결과 값

  • Slice
    • 내가 파라미터로 준 Pageable 의 limit 보다 한개를 더 요청한다.
    • Paging query
    • 한개 더 가져와서 다음 페이지가 있음을 알게하도록 (더보기 버튼) 하는 구현을 많이함.
  • Page
    • Paging Query + Count Query
결과 값 사용 가능 함수 리턴 값 기능
Page getContent() List<T> 페이징 조건에 맞는 결과 값 (List<T>) 을 가져온다.
  getTotalElements() long count 쿼리에 대한 결과 값을 가져온다.
  getNumber() int 몇번째 페이지인지 반환한다.
  getTotalPages() int 총 페이지수를 반환한다.
  isFirst() boolean 첫번째 페이지인지 알 수 있다.
  hasNext() boolean 다음 페이지가 존재하는지 알 수 있다.
Slice getContent() List<T> 페이징 조건에 맞는 결과 값 (List<T>) 을 가져온다.
  getNumber() int 몇번째 페이지인지 반환한다.
  isFirst() boolean 첫번째 페이지인지 알 수 있다.
  hasNext() boolean limit 보다 한개 더 요청을 하기 때문에 다음 페이지가 존재하는지 알 수 있다.

 

Count Query를 분리할 수 있다.

@Query(value = "select m from Member m left join m.team t", 
        countQuery = "select count(m) from Member m")
Page<Member> findByAge(int age, Pageable pageable);

 

DTO 로 변환하여 api에서 리턴하자

Page<Member> page = memberRepository.findByAge(age, pageRequest);
Page<MemberDto> toMap = page.map(member -> new MemberDto(member.getId(), member.getUsername(), null));

8. 벌크성 수정 쿼리

 

Spring Data JPA

  • @Modifying(clearAutomatically = true)
  • 반환값은 int
@Modifying
@Query("update Member m set m.age = m.age + 1 where m.age >= :age")
int bulkAgePlus(@Param("age") int age);

9. @EntityGraph

 

Spring Data Jpa 에서는 fetch join 을 편리하게 할 수 있다.

 

ex) fetch join

@Query("select m from Member m left join fetch m.team")
List<Member> findMemberFetchJoin();

 

ex) @EntityGraph

@EntityGraph(attributePaths = {"team"})
List<Member> findAll();
@EntityGraph(attributePaths = {"team"})
List<Member> findEntityGraphByUsername(@Param("username") String username);

10. JPA Hint & Lock

 

1. ReadOnly 기능

  • 100% 조회용으로만 사용할 것이다.
  • dirty checking 최적화
@QueryHints(value = @QueryHint(name = "org.hibernate.readOnly", value = "true"))
Member findReadOnlyByUsername(String username);

 

2. Lock

  • DB에 Lock 을 걸 수 있다.

ex) 쿼리문에 select for update (lock 을 거는 select 가 추가되는 모습)

@Lock(LockModeType.PESSIMISTIC_WRITE)
List<Member> findLockByUsername(String username);

// 쿼리문
select
    member0_.member_id as member_i1_0_,
    member0_.age as age2_0_,
    member0_.team_id as team_id4_0_,
    member0_.username as username3_0_
from
    member member0_
where
    member0_.username=? for update

 

'강의 정리 > 스프링 데이터 JPA' 카테고리의 다른 글

3. 확장 기능  (0) 2021.01.14
1. extends JpaRepository  (0) 2021.01.10