8장: Spring Data JPA 활용
8-2 JPQL
JPQL은 JPA Query Language의 줄임말로 JPA에서 사용할 수 있는 쿼리를 의미한다. JPQL의 문법은 SQL과 매우 비슷한 것이 특징이다.
8-3 쿼리 메서드 살펴보기
리포지토리는 JpaRepository를 상속받는 것만으로도 다양한 CRUD 메서드를 제공한다.
8-3-2 쿼리 메서드의 주제 키워드
주요 키워드
- find...By
- read...By
- get...By
- query...By
- search...By
- stream...By
리턴 타입으로 Collection이나 Stream에 속한 하위 타입을 설정할 수 있다.
exisits...By
특정 데이터가 존재하는지 확인하는 키워드이다. 리턴 타입은 boolean 타입이다.
count...By
조회 쿼리를 수행한 후 쿼리 결과로 나온 레코드의 개수를 리턴한다.
delete...By, remove...By
삭제 쿼리를 수행한다. 리턴타입은 없거나 삭제한 횟수를 리턴한다.
...First<number>..., ...Top<number>...
쿼리를 통해 조회된 결괏값의 개수를 제한하는 키워드이다. 동일한 동작을 수행하며, 주제와 By 사이에 위치한다. 일반적으로 이 키워드는 한 번의 동작으로 여러 건을 조회할 때 사용되며, 단 건으로 조회하기 위해서는 <number>를 생략하면 된다.
8-3-3 쿼리 메서드의 조건자 키워드
Is
값의 일치를 조건으로 사용하는 조건자 키워드이다. 생략되는 경우가 많으며 Equals와 동일한 기능을 한다.
(Is)Not
값의 불일치를 조건으로 사용하는 조건자 키워드이다. Is는 생략하고 Not 키워드만 사용할 수도 있다.
(Is)Null, (Is)NotNull
값이 null인지 검사하는 조건자 키워드이다.
(Is)True, (Is)False
boolean 타입으로 지정된 칼럼값을 확인하는 키워드이다. 엔티티에 boolean 타입을 사용하는 칼럼이 없으면 에러가 발생한다.
And, Or
여러 조건을 묶을 때 사용한다.
(Is)GreaterThan, (Is)LessThan, (Is)Between
숫자나 datetime 칼럼을 대상으로 한 비교 연산에 사용할 수 있는 조건자 키워드이다. GreaterThan, LessThan 키워드는 비교 대상에 초과/미만의 개념으로 비교연산을 수행하고, 경곗값을 포함하려면 Equal 키워드를 추가하면 된다.
(Is)StartingWith(==StartsWith), (Is)EndingWith(==EndsWith), (Is)Containing(==Contains), (Is)Like
칼럼값에서 일부 일치 여부를 확인하는 조건자 키워드이다. SQL 쿼리문에서 값의 일부를 포함하는 값을 추출할 때 사용하는 '%' 키워드와 동일한 역할을 하는 키워드이다. 자동으로 생성되는 SQL문을 보면 Containing 키워드는 문자열의 양 끝, StartingWith 키워드는 문자열의 앞, EndingWith 키워드는 문자열의 끝에 '%'가 배치된다. Like 키워드는 코드 수준에서 메서드를 호출하면서 전달하는 값에 %를 명시적으로 입력해야 한다.
8-4-1 정렬 처리하기
일반적인 쿼리문에서 정렬을 사용할 때는 ORDER BY 구문을 사용한다. 쿼리 메서드도 정렬 기능에 동일한 키워드가 사용된다.
OrderBy 키워드 뒤에 정렬하고자 하는 칼럼과 오름차순/내림차순을 설정한다. Asc(오름차순), Desc(내림차순)
8-4-2 페이징 처리
페이징이란 데이터베이스의 레코드를 개수로 나눠 페이지를 구분하는 것을 의미한다.
JPA에서는 이 같은 페이징 처리를 위해 Page와 Pagealbe을 사용한다. 리턴타입으로 Page를 설정하고 매개변수에는 Pageable 타입의 객체를 정의한다.
of 메서드 | 매개변수 설명 | 비고 |
of(int page, int size) | 페이지 번호(0부터 시작), 페이지당 데이터 개수 | 데이터를 정렬하지 않음 |
of(int page, int size, Sort) | 페이지 번호, 페이지당 데이터 개수, 정렬 | Sort에 의해 정렬 |
of(int page, int size, Direction, String...properties) |
페이지 번호, 페이지당 데이터 개수, 정렬 방향, 속성(칼럼) | Sort.by(direction, properties)에 의해 정렬 |
8-5 @Query 어노테이션 사용하기
@Query 어노테이션을 사용해 직접 JPQL을 작성할 수도 있다.
JPQL을 사용하면 JPA 구현체에서 자동으로 쿼리 문장을 해석하고 실행하게 된다. 만약 데이터베이스를 다른 데이터베이스로 변경할 일이 없다면 직접 해당 데이터베이스에 특화된 SQL을 작성할 수 있으며, 주로 튜닝된 쿼리를 사용하고자 할 때 직접 SQL을 작성한다.
8-6 QueryDSL 적용하기
메서드의 이름을 기반으로 생성하는 JPQL의 한계는 @Query 어노테이션을 통해 대부분 해소할 수 있지만 직접 문자열을 입력하기 때문에 컴파일 시점에 에러를 잡지 못하고 런타임 에러가 발생할 수 있다. 쿼리의 문자열이 잘못된 경우에는 애플리케이션이 실행된 후 로직이 실행되고 나서야 오류를 발견할 수 있다. 이러한 이유로 개발 환경에서는 문제가 없는 것처럼 보이다가 실제 운영 환경에 애플리케이션을 배포하고 나서 오류가 발견되는 리스크를 유발한다.
이 같은 문제를 해결하기 위해 사용되는 것이 QueryDSL이다. QueryDSL은 문자열이 아니라 코드로 쿼리를 작성할 수 있도록 도와준다.
8-6-1 QueryDSL이란?
QueryDSL은 정적 타입을 이용해 SQL과 같은 쿼리를 생성할 수 있도록 지원하는 프레임워크이다. 문자열이나 XML 파일을 통해 쿼리를 작성하는 대신 QueryDSL이 제공하는 플루언트(Fluent) API를 활용해 쿼리를 생성할 수 있다.
8-6-2 QueryDSL의 장점
- IDE가 제공하는 코드 자동 완성 기능을 사용할 수 있다.
- 문법적으로 잘못된 쿼리를 허용하지 않는다. 따라서 정상적으로 활용된 QueryDSL은 문법 오류를 발생시키지 않는다.
- 고정된 SQL 쿼리를 작성하지 않기 때문에 동적으로 쿼리를 생성할 수 있다.
- 코드로 작성하므로 가독성 및 생산성이 향상된다.
- 도메인 타입과 프로퍼티를 안전하게 참조할 수 있다.
8-6-4 기본적인 QueryDSL 사용하기
QueryDSL을 사용하기 위해서는 JPAQuery 객체를 사용한다. JPAQuery는 엔티티 매니저(EntityManager)를 활용해 생성한다.
반환 메서드
- List<T> fetch(): 조회 결과를 리스트로 반환한다.
- T fetchOne(): 단 건의 조회 결과를 반환한다.
- T fetchFirst(): 여러 건의 조회 결과 중 1건을 반환한다. 내부 로직을 살펴보면 '.limit(1).fetchOne()'으로 구현돼 있다.
- Long fetchCount(): 조회 결과의 개수를 반환한다.
- QueryResult<T> fetchResults(): 조회 결과 리스트와 개수를 포함한 QueryResults를 반환한다.
JPAQuery 객체를 사용하지 않고 JPAQueryFactory를 활용해서도 작성할 수 있다.
JPAQueryFactory 객체를 @Bean 객체로 등록해 두면 매번 초기화를 하지 않고 스프링 컨테이너에서 가져다 쓸 수 있다.
8-6-5 QuerydslPredicateExecuotr, QuerydslRepositorySupport 활용
스프링 데이터 JPA에서는 QueryDSL을 더욱 편하게 사용할 수 있게 QuerydslPredicateExecuotr 인터페이스와 QuerydslRepositorySupport 클래스를 제공한다.
QuerydslPredicateExecuotr 인터페이스
QuerydslPredicateExecuotr는 JpaRepository와 함께 리포지토리에서 QueryDSL을 사용할 수 있게 인터페이스를 제공한다.
QuerydslPredicateExecuotr 인터페이스의 메서드는 대부분 Predicate 타입을 매개변수로 받는다. Predicate는 표현식을 작성할 수 있게 QueryDSL에서 제공하는 인터페이스이다.
QuerydslPredicateExecuotr를 활용하면 더욱 편하게 QueryDSL을 사용할 수 있지만 join이나 fetch 기능은 사용할 수 없다는 단점이 있다.
QuerydslRepositorySupport 추상 클래스 사용하기
가장 보편적으로 사용하는 방식은 CustomRepository를 활용해 리포지토리를 구현하는 방식이다.
8-7 [ 한걸음 더 ] JPA Auditing 적용
JPA에서 'Audit'이란 '감시하다'라는 뜻으로, 각 데이터마다 '누가', '언제' 데이터를 생성했고 변경했는지 감시한다는 의미로 사용된다.
엔티티 클래스에 대표적으로 많이 사용되는 필드
- 생성 주체
- 생성 일자
- 변경 주체
- 변경 일자
이러한 필드들을 매번 값을 주입해야 하는 번거로움을 줄이기 위해 Spring Data JPA에서는 자동으로 값을 넣어주는 기능을 제공한다.
8-7-2 BaseEntity 만들기
코드의 중복을 없애기 위해서 각 엔티티에 공통으로 들어가는 칼럼(필드)을 하나의 클래스로 빼는 작업을 수행한다.
주요 어노테이션
- @MappedSuperclass: JPA의 엔티티 클래스가 상속받을 경우 자식 클래스에게 매핑 정보를 전달한다.
- @EntityListeners: 엔티티를 데이터베이스에 적용하기 전후로 콜백을 요청할 수 있게 하는 어노테이션이다.
- AuditingEntityListener: 엔티티의 Auditing 정보를 주입하는 JPA 엔티티 리스너 클래스이다.
- @CreateDate: 데이터 생성 날짜를 자동으로 주입하는 어노테이션이다.
- @LastModifiedDate: 데이터 수정 날짜를 자동으로 주입하는 어노테이션이다.
'Zerobase > 북 스터디' 카테고리의 다른 글
스프링 부트 핵심 가이드(장정우 지음) ch.10 (0) | 2023.08.01 |
---|---|
스프링 부트 핵심 가이드(장정우 지음) ch.9 (0) | 2023.07.23 |
스프링 부트 핵심 가이드(장정우 지음) ch.6 (0) | 2023.07.09 |
스프링 부트 핵심 가이드(장정우 지음) ch.5 (0) | 2023.07.02 |
스프링 부트 핵심 가이드(장정우 지음) ch.4 (0) | 2023.07.02 |