참고 https://docs.spring.io/spring-data/jpa/docs/current/reference/html/
// 예제
public interface MemberRepository extends JpaRepository<Member, Long> {
List<Member> findByUsernameAndAgeGreaterThan(String username, int age);
}
- Spring Data JPA는 메소드 이름을 분석해서 JPQL을 생성하고 실행
- 쿼리 메소드 필터 조건 - 공식문서 참고(위에 링크)
- 제공하는 쿼리 메소드 기능
- 조회
- COUNT
- EXISTS
- 삭제
- DISTINCT
- LIMIT
- 참고사항
- 이 기능은 엔티티의 필드명이 변경되면 인터페이스에 정의한 메서드 이름도 꼭 함께 변경해야함
- 그렇지 않으면 애플리케이션을 시작하는 시점에 오류 발생
- 이렇게 애플리케이션 로딩 시점에 오류를 인지할 수 있는 것이 스프링 데이터 JPA의 매우 큰 장점
- JPA NamedQuery -> 잘 사용안함
// @NamedQuery 어노테이션으로 Named 쿼리 정의
@Entity
@NamedQuery(
name="Member.findByUsername",
query="select m from Member m where m.username = :username")
public class Member {
...
}
// JPA 직접 사용해서 Named 쿼리 호출
public class MemberRepository {
public List<Member> findByUsername(String username) {
...
List<Member> resultList =
em.createNamedQuery("Member.findByUsername", Member.class)
.setParameter("username", username)
.getResultList();
}
}
// 스프링 데이터 Jpa로 NamedQuery 사용
@Query(name = "Member.findByUsername")
List<Member> findByUsername(@Param("username") String username);
// 스프링 데이터 Jpa로 Named 쿼리 호출
public interface MemberRepository
extends JpaRepository<Member, Long> { //** 여기 선언한 Member 도메인 클래스
List<Member> findByUsername(@Param("username") String username);
}
- 참고
- 스프링 데이터 JPA를 사용하면 실무에서 Named Query를 직접 등록해서 사용하는 일은 드물다.
- 대신 @Query를 사용해서 리파지토리 메소드에 쿼리를 직접 정의
- Named Query (가장 큰)장점 -> 애플리케이션 로딩시점에 오류를 잡을 수 있음
@Query, 리포지토리에 쿼리 메소드 정의 하기(많이 씀)
public interface MemberRepository extends JpaRepository<Member, Long> {
@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);
}
- @org.springframework.data.jpa.repository.Query 어노테이션 사용
- 실행할 메서드에 정적 쿼리를 직접 작성하므로 이름 없는 Named 쿼리라 할 수 있음
- JPA Named 쿼리처럼 애플리케이션 실행 시점에 문법 오류를 발견할 수 있음 (엄청 큰 장점)
- 참고
- 실무에서는 메소드 이름으로 쿼리 생성 기능은 파라미터가 증가하면 메서드 이름이 매우 지저분해짐.
- 그래서 @Query 기능을 자주 사용
- Query, 값, DTO 조회하기
- 단순히 값 하나 조회
@Query("select m.username from Member m")
List<String> findUsernameList();
- JPA 값 타입(@Embedded)도 이방식으로 조회 가능
- DTO로 직접 조회
@Query("select new study.datajpa.dto.MemberDto(m.id, m.username, t.name) " +
"from Member m join m.team t")
List<MemberDto> findMemberDto();
- 주의
- DTO로 직접 조회 하려면 JPA의 'new' 명령어를 사용해야 함
- 그리고 생성자가 맞는 DTO가 필요 (JPA 사용방식과 동일)
- 반환타입
List<Member> findByUsername(String name); //컬렉션
Member findByUsername(String name); //단건
Optional<Member> findByUsername(String name); //단건 Optional
- 조회 결과가 많거나, 없으면?
- 컬렉션 : 결과없음, 빈 컬렉션 반환
- 단건조회
- 결과 없음 : Null 반환
- 결과가 2건 이상 : 'javax.persistence.NonUniqueResultException' 예외 발생
// 페이징과 정렬 사용 예제
Page<Member> findByUsername(String name, Pageable pageable); //count 쿼리 사용
Slice<Member> findByUsername(String name, Pageable pageable); //count 쿼리 사용 안 함
List<Member> findByUsername(String name, Pageable pageable); //count 쿼리 사용 안 함
List<Member> findByUsername(String name, Sort sort);
// Page 인터페이스
public interface Page<T> extends Slice<T> {
int getTotalPages(); //전체 페이지 수 longgetTotalElements();//전체 데이터 수
<U> Page<U> map(Function<? super T, ? extends U> converter); //변환기
}
// Slice 인터페이스
public interface Slice<T> extends Streamable<T> {
intgetNumber(); // 현재 페이지
intgetSize(); // 페이지 크기
int getNumberOfElements(); // 현재 페이지에 나올 데이터 수
List<T> getContent(); // 조회된 데이터
boolean hasContent(); // 조회된 데이터 존재 여부
Sort getSort(); // 정렬 정보
boolean isFirst(); // 현재 페이지가 첫 페이지 인지 여부
boolean isLast(); // 현재 페이지가 마지막 페이지 인지 여부
boolean hasNext(); // 다음 페이지 여부
boolean hasPrevious(); // 이전 페이지 여부
Pageable getPageable(); // 페이지 요청 정보
Pageable nextPageable(); // 다음 페이지 객체
PageablepreviousPageable(); // 이전 페이지 객체
<U> Slice<U> map(Function<? super T, ? extends U> converter); // 변환기
}
'기록하기' 카테고리의 다른 글
Docker 삭제 명령어 (0) | 2023.11.16 |
---|---|
Amazon java 17 다운 (0) | 2023.11.16 |
Springboot + Docker + Github action (0) | 2023.11.15 |
Redis (1) (1) | 2023.11.15 |
Day + 29 (0) | 2023.11.13 |