1. Spring Data JPA 쿼리 메소드 개요
Spring Data JPA는 JPA를 더 쉽고 편리하게 사용할 수 있도록 지원하는 프레임워크다. 기본적인 CRUD 기능뿐만 아니라 자동으로 쿼리를 생성하고 실행하는 기능도 제공한다.
대표적인 쿼리 생성 방식
- 메소드 이름 기반 쿼리: findByUsernameAndAgeGreaterThan
- NamedQuery: @NamedQuery 활용
- @Query 어노테이션 활용: 직접 JPQL 작성
2. 쿼리 메소드 3가지 유형
유형 | 설명 | 예제 |
메소드 이름 기반 쿼리 | 메소드 이름을 분석하여 JPQL 자동 생성 | findByUsernameAndAgeGreaterThan |
NamedQuery | 엔티티 클래스에 미리 정의된 JPQL 쿼리를 사용 | @NamedQuery(name="Member.findByUsername") |
@Query 어노테이션 | JPQL을 직접 작성하여 실행 | @Query("SELECT m FROM Member m WHERE m.username = :username") |
3. 메소드 이름 기반 쿼리
Spring Data JPA는 메소드 이름을 기반으로 자동으로 JPQL을 생성한다.
순수 JPA 방식
public List<Member> findByUsernameAndAgeGreaterThan(String username, int age) {
return em.createQuery("SELECT m FROM Member m WHERE m.username = :username AND m.age > :age")
.setParameter("username", username)
.setParameter("age", age)
.getResultList();
}
Spring Data JPA 방식
public interface MemberRepository extends JpaRepository<Member, Long> {
List<Member> findByUsernameAndAgeGreaterThan(String username, int age);
}
자동 생성되는 JPQL
SELECT m FROM Member m WHERE m.username = ?1 AND m.age > ?2
쿼리 키워드 목록
키워드 | 설명 |
findBy | 조회 |
countBy | 개수 조회 |
existsBy | 존재 여부 확인 |
deleteBy | 삭제 |
top, first | 제한된 개수 조회 |
4. NamedQuery 활용
NamedQuery 정의
@Entity
@NamedQuery(
name = "Member.findByUsername",
query = "select m from Member m where m.username = :username"
)
public class Member {
...
}
NamedQuery 호출
( 순수 JPA 방식 )
public class MemberRepository {
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);
- 메서드 이름만으로도 NamedQuery를 자동으로 호출 가능.
5. @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);
}
장점
- 복잡한 쿼리도 쉽게 정의 가능
- JPQL 문법 오류를 애플리케이션 실행 전에 감지 가능
6. DTO 조회
DTO를 직접 조회
@Query("SELECT new com.example.MemberDto(m.id, m.username, t.name) FROM Member m JOIN m.team t")
List<MemberDto> findMemberDto();
DTO 클래스
@Data
public class MemberDto {
private Long id;
private String username;
private String teamName;
public MemberDto(Long id, String username, String teamName) {
this.id = id;
this.username = username;
this.teamName = teamName;
}
}
7. 페이징과 정렬
페이징 메소드
public interface MemberRepository extends JpaRepository<Member, Long> {
Page<Member> findByAge(int age, Pageable pageable);
}
페이징 실행 코드
PageRequest pageRequest = PageRequest.of(0, 3, Sort.by(Sort.Direction.DESC, "username"));
Page<Member> page = memberRepository.findByAge(10, pageRequest);
8. 벌크 연산
대량의 데이터를 수정하는 경우 @Modifying 어노테이션을 사용한다.
대량 수정 쿼리
@Modifying
@Query("UPDATE Member m SET m.age = m.age + 1 WHERE m.age >= :age")
int bulkAgePlus(@Param("age") int age);
@Modifying(clearAutomatically = true)
주의: 벌크 연산은 영속성 컨텍스트를 무시하고 실행되므로, 영속성 컨텍스트를 초기화해야 한다.
9. @EntityGraph (N+1 문제 해결)
Spring Data JPA는 @EntityGraph를 사용하여 연관된 엔티티를 한 번에 조회할수도 있다.
@EntityGraph(attributePaths = {"team"})
List<Member> findByUsername(String username);
- 페치 조인(FETCH JOIN)과 유사한 기능 제공.
10. JPA 힌트 & 락
JPA 힌트 사용
@QueryHints(value = @QueryHint(name = "org.hibernate.readOnly", value = "true"))
Member findReadOnlyByUsername(String username);
- 조회 전용(read-only)로 설정하면 성능이 최적화됨.
락(Lock) 사용
@Lock(LockModeType.PESSIMISTIC_WRITE)
List<Member> findByUsername(String name);
- 동시성 문제를 해결하기 위해 Pessimistic Lock 사용 가능.
반응형
'Backend > JPA' 카테고리의 다른 글
JPA (Spring Data JPA)- Auditing을 활용한 엔티티 자동 생성 및 수정 정보 기록 (0) | 2025.03.12 |
---|---|
JPA (Spring Data JPA) - 사용자 정의 리포지토리 개념과 구현 방법 (0) | 2025.03.12 |
JPA - 값 타입 매핑: 기본 개념부터 실무 적용까지 (0) | 2025.02.27 |
JPA - 영속성 전이(CASCADE)와 고아 객체(부모 엔티티를 통해 자식의 생명주기 관리) (0) | 2025.02.24 |
JPA - 프록시와 지연 로딩 (불필요한 데이터 조회 방지) (0) | 2025.02.24 |