728x90
반응형
728x90
쿼리 메서드
- 데이터베이스 쿼리를 생성하기 위해 메서드 이름을 사용하여 간편하게 구현할 수 있는 기능
- 개발자가 쿼리를 작성할 때 SQL을 직접 작성하는 대신 메서드 이름을 기반으로 JPA가 자동으로 쿼리를 생성
- JpaRepository를 상속받는 인터페이스에 구현
기본 구조
- 접두어를 사용한 메서드 이름으로 조건을 선택
- 조회: find…By , read…By , query…By get…By,... 에 주로 식별하기 위한 이름이나 설명이 들어가거나 생략 가능
//예시: 둘 다 username을 통해 조회하는 메서드
List<User> findByUsername(String username)
List<User> findUserByUsername(String username)
- COUNT: count…By, count를 반환하는 메서드 -> 반환 타입 long
//예시: 특정 나이의 User 객체 수 반환
long countByAge(int age)
long countUserByAge(int age)
- EXISTS: exists…By, 존재 여부를 반환하는 메서드 -> 반환타입 boolean
//예시: 특정 이름의 User가 존재하는지 확인
boolean existsByUsername(String name)
boolean existsUserByUsername(String name)
- 삭제: delete…By, remove…By, 데이터를 삭제하는 메서드 -> 반환타입 long, int, void
//예시: 특정 이름의 User를 삭제하고 처리한 결과 개수를 반환
long deleteByUsername(String username)
long deleteUserByUsername(String username)
- DISTINCT: findDistinct, findMemberDistinctBy, 중복된 데이터를 제거하고 고유한 결과만 반환 find에 Distinct 키워드만 추가
//예시: 특정 이름의 User 객체 중 중복을 제거하고 반환
List<User> findDistinctByUsername(String username)
- LIMIT: findFirst3, findFirst, findTop, findTop3, 반환할 결과의 개수를 제한
//예시: 나이가 가장 많은 User 객체 반환
User findFirstByOrderByAgeDesc()
기본 JPA NamedQuery
- 사전 정의된 쿼리로 코드에서 재사용할 수 있도록 이름을 붙인 쿼리
- 실행 시 컴파일되어 사전에 쿼리 오류를 확인 가능
사용 방법
- 엔티티 클래스에 @NamedQuery 어노테이션으로 정의
//예시
@NamedQuery(name="User.findByUsername", query="select u from User u where u.username = :username")
- 사용 시 엔티티 매니저의 createNamedQuery로 호출하여 사용
//예시
createNamedQuery(" User.findByUsername", User.class)
Spring Data Jpa NamedQuery
- 구현한 Repository에서 선언한 메서드 위 @Query 어노테이션의 name 속성으로 사용
- @Query가 없더라도 JPA는 도메인 클래스 이름 + . + 메서드 이름으로 Named 쿼리를 찾아서 실행
//예시
@Query(name = " User.findByUsername")
List<User> findByUsername (@Param("username") String username);
Repository 쿼리 메서드
- 리포지토리에 작성한 메서드에 직접 쿼리를 정의하여 사용하는 방법
- @Query 어노테이션을 통해 사용
- 이름 기반의 쿼리 메서드는 조건이 많아질수록 이름이 길어져 @Query를 통해 정의한 방법을 주로 사용
//예시
@Query("select u from User u where u.username= :username and u.age = :age")
List<User> findUser(@Param("username") String username, @Param("age") int age);
@Query DTO 조회
- JPA와 같이 new 명령어를 통해 DTO 를 사용한 조회 가능
@Query("select new com.example.dto.UserDto(u.id, u.username, g.name) " +
"from User u join u.group g")
List<UserDto> findUserDto();
파라미터 바인딩
- 위치 기반과 이름 기반 파라미터 바인딩 제공
- 컬렉션 타입 파라미터로 IN 절 지원
select u from User u where u.username = ?0 //위치 기반
select u from User u where u.username = :name //이름 기반
//컬렉션 타입
@Query("select u from User u where u.username in :names")
List<User> findByNames(@Param("names") List<String> names)
반환 타입
- 유연한 반환 타입 제공, (단건, 컬렉션, Optional)
- 조회 결과에 따른 반환
- 컬렉션
- 결과 없음 -> 빈 컬렉션 반환
- 단건
- 결과 없음 -> null
- 2개 이상 -> javax.persistence.NonUniqueResultException 예외 발생
- 컬렉션
//예시
List<User> findByUsername(String name); //컬렉션
User findByUsername(String name); //단건
Optional<User> findByUsername(String name); //단건 Optional
Paging
- 페이징 기능 사용시 Page, Slice 반환 타입 제공
- Page <T>: 추가 count 쿼리 결과를 포함하는 페이징
- Slice <T>: 추가 count 쿼리 없이 다음 페이지만 확인 가능(요청한 페이지 크기보다 하나 더 많은 항목을 조회)
- Pageable 인터페이스로 페이징 정보 정의
- 추가적으로 정렬 조건 정의 가능
- 페이지 시작은 0
- map 메서드 제공으로 페이징을 유지한 채 DTO 변환 가능
//예시
Page<User> findByUsername(String name, Pageable pageable); //count 쿼리 사용
Slice<User> findByUsername(String name, Pageable pageable); //count 쿼리 사용 안함
List<User> findByUsername(String name, Pageable pageable); //count 쿼리 사용 안함
//페이징 정보를 담은 구현체를 파라미터로 사용
PageRequest pageRequest = PageRequest.of(0, 3, Sort.by(Sort.Direction.DESC, "username"));
//map을 사용한 DTO 변환
Page<UserDto> dtoPage = page.map(u -> new UserDto());
주요 메서드
- getTotalPages(): 전체 페이지 수 반환
- getTotalElements(): 전체 데이터 수 반환
- getNumber(): 현재 페이지 반환
- getSize(): 페이지 크기 반환
- getNumberOfElements(): 현재 페이지에 나올 데이터 수 반환
- getContent(): 조회된 데이터 반환
- hasContent(): 조회된 데이터 존재 여부 반환
- isFirst(), isLast(): 현재 페이지가 첫(마지막) 페이지 인지 반환
- hasNext(), hasPrevious(): 다음(이전) 페이지 존재 여부 반환
벌크 쿼리
- 여러 레코드를 동시에 업데이트할 때 사용하는 쿼리
- 벌크 수정 삭제 쿼리는 @Modifying 어노테이션을 사용
- clearAutomatically 옵션으로 벌크 쿼리 실행 후 영속성 컨텍스트 초기화 가능 (기본값 false)
- 영향을 받은 엔티티 수를 반환
//예시
@Modifying
@Query("UPDATE User u SET u.age = u.age + 1")
int incrementAllUserAges();
@EntityGraph
- 특정 엔티티를 조회할 때 관련된 엔티티를 미리 로딩
- 지연 로딩 설정 된 객체를 fetch join을 사용하는 것과 동일한 기능
- @EntityGraph 어노테이션 통해 적용
- attributepaths 속성으로 즉시 로딩 할 객체를 선택
//공통 메서드 오버라이드
@Override
@EntityGraph(attributePaths = {"group"})
List<User> findAll();
//JPQL + 엔티티 그래프
@EntityGraph(attributePaths = {"group"})
@Query("select u from User u")
List<User> findMemberEntityGraph();
//쿼리 메서드
@EntityGraph(attributePaths = {"group"})
List<User> findByUsername(String username)
실전! 스프링 데이터 JPA 강의 | 김영한 - 인프런 (inflearn.com) 강의 내용 참고
728x90
'백엔드 > Spring' 카테고리의 다른 글
[Spring] Querydsl (1) | 2024.09.25 |
---|---|
[Spring] Spring Data Jpa 확장 기능 (0) | 2024.09.24 |
[Spring] Spring Data JPA (2) | 2024.09.22 |
[Spring] JPA 컬렉션 조회 최적화 & OSIV (1) | 2024.09.21 |
[Spring] JPA 지연 로딩 & 조회 성능 최적화 (0) | 2024.09.20 |