북 스터디/스프링 부트 핵심가이드

Spring Data JPA

EnoughTT 2023. 4. 1. 15:05

JPQL

JPA Query Language 의 줄임말로 JPA에서 사용할 수 있는 쿼리
엔티티 객체를 대상으로 수행하는 쿼리
매핑된 엔티티의 이름과 필드의 이름을 사용

 

쿼리 메서드의 생성

쿼리 메서드는 주제(Subject)서술어(Predicate)로 구분

' find...By ', ' exists...By ' 와 같은 키워드로 쿼리의 주제를 정하며, ' By '는 서술어의 시작을 나타내는 구분자 역할을 함.

서술어 부분은 검색 및 정렬 조건을 지정하는 영역 / 엔티티의 속성으로 정의할 수 있고, AND 나 OR 를 사용해서 조건을 확장하는 것도 가능.

// (리턴타입) + {주제 + 서술어(속성)}
List<Customer> findByEmailAndName(String email, String name);

쿼리 메서드의 주제 키워드

  • find...By
  • read...By
  • get...By
  • query...By
  • search...By
  • stream...By

' ... ' 표시 영역 : 도메인 (엔티티) 표현 가능

      → 리포지토리에서는 도메인 설정 후 메서드를 사용하기 때문에 중복으로 판단해 생략함.

 

키워드 키워드 설명 리턴타입 SQL
exists...By 특정 데이터 존재 여부 boolean IF(EXISTS (SELECT ~
WHERE EXISTS (SELECT ~
count...By 레코드 개수 반환 숫자(long) SELECT COUNT(*)
delete...By
remove...By
삭제 쿼리 리턴타입 없음
삭제한 횟수
DELETE FROM TABLE ~
...First<number>...
Top<number>
결과값 개수 제한 여러건 조회 LIMIT 1
TOP (1)

 

쿼리 메서드의 조건자 키워드

 

키워드 키워드 설명 SQL
Is(=is) 값 일치를 조건 WEHRE ITEM = 
(Is)Not 값 불일치 조건 WHERE ITEM <> 'FF'
WHERE ITEM != 'SS'
(Is)Null
(Is)NotNull
null 인지 검사 WHERE IS NULL
WEHRE IS NOT NULL
(Is)True
(Is)False
boolean 타입으로 지정된
컬럼값 확인
 
And
Or
여러개의 조건으로 묶을 때 WHERE ITEM =
AND (OR) ITEM2 =
(Is)GreaterThen
(Is)GreaterThenEqual
(Is)LessThen
(Is)Between
비교 연산 사용 WEHRE NUMBER >
WHERE NUMBER >=
WHERE NUMBER <
WEHRE NUMBER BETWEEN AND
(Is)StartingWith(= StartsWith)
(Is)EndingWith(= EndsWith)
(Is)Containing(= Contains)
(Is)Like

컬럼값 일부 일치 여부
Like는 ' % ' 명시적
WEHRE ITEM LIKE '%S'
WEHRE ITEM LIKE 'S%'
WHERE ITEM LIKE '%S%'
WEHRE ITEM LIKE (명시적)'%S'

 

정렬과 페이징 처리

  • 정렬 처리
/*
	Asc - 오름차순, Desc - 내림차순
*/
// 고객정보를 이메일로 검색 후 id로 오름차순 정렬
List<Customer> findByEmailOrderByidAsc(String email);

// 고객정보를 이메일로 검색 후 id로 내림차순 정렬
List<Customer> findByEmailOrderByidDesc(String email);

-------

/*
	정렬 기준 여러개 사용
*/
// 고객정보를 이메일로 검색 후 id기준으로 오름차순 정렬후 Name기준으로 내림차순 정렬
List<Customer> findByEmailOrderByidAscNameDesc(String email);

-------

/* 	
	위와 같이 사용하면 메서드의 이름이 길어져 가독성↓
	매개변수를 활용한 쿼리 정렬
*/
List<Customer> findByEmail(String email, Sort sort);

/*
	테스트 시 작성 코드
    Sort 클래스는 Order 객체를 활용해 정렬 기준 생성
    여러기준을 사용 할 경우 ' , ' 사용
*/
customerRepository.findByEmail(email, Sort.by(Order.asc("id")));
customerRepository.findByEmail(email, Sort.by(Order.asc("id"), Order.desc("Name")));

 

  • 페이징 처리
페이징이란 데이터베이스의 레코드를 개수로 나눠 페이지를 구분하는 것
25개의 레코드가 있다면 7개씩 총 4개의 페이지로 구분하고 특정 페이지를 가져올 수 있음
/*
	페이징 처리 메서드
*/
// 리턴 타입 : Page, 매개변수 : Pageable 타입 객체
Page<Customer> findByEmail(String email, Pageable pageable); 
 
/*
	호출 시
    PageRequest 는 Pageable 구현체임
    PageRequest 는 of 메서드를 통해 객체 생성
*/
Page<Customer> customerPage = customerRepository.findByEmail(email, PageRequest.of(0, 2));

 

@Query 어노테이션 사용

다른 데이터베이스로 변경할 일이 없다면
직접 SQL을 작성 할 수 있음. 주로 튜닝된 쿼리를 사용하고자 작성
/*
	@Query 어노테이션 사용 메서드
*/
@Query("SELECT EMAIL FROM CUSTOMER AS CT WEHRE CT.EMAIL = ?1")
List<Customer> findByEmail(String email);

/*
	위 쿼리는 파라미터의 순서가 바뀌면 오류 발생 가능성 ↑
    @Param 어노테이션 사용
*/
@Query("SELECT EMAIL FROM CUSTOMER CT WEHRE CT.EMAIL = :email")
List<Customer> findByEmailParam(@Param("email") String email);

 

QueryDSL 적용

정적 타입을 이용해 SQL과 같은 쿼리를 생성할 수 있도록 지원하는 프레임워크
플루언트(Fluent) API를 활용해 쿼리 생성
개인적인 생각으로는 C# LINQ 와 비슷
  • QueryDSL 의 장점
    • IDE가 제공하는 코드 자동 완성 기능 사용 가능
    • 잘못된 쿼리 허용하지 않음. 문법 오류 발생 없음
    • 동적 쿼리 생성 가능
    • 가독성 및 생산성 ↑
    • 도메인 타입과 프로퍼티를 안전하게 참조 가능
  • QueryDSL 의 단점
    • QueryDSL 구문과 그 개념 및 제한 사항을 숙지해야함
    • 모든 데이터베이스의 고급 기능을 지원하지 않을 수 있음
    • 새 라이브러리를 추가해야하므로 오버헤드가 증가 할 수 있음
      라이브러리 업데이트 시 상당한 코드 변경이 있을 수 있음
    • 디버깅이 어려움
    • 복잡한 쿼리의 경우 생성 및 실행 시간이 길어 질 수 있음

QueryDSL 을 사용하려면 의존성을 추가 후 APT 플러그인을 추가해야함.