SpringData 쿼리와 QueryDSL
:: SpringData 쿼리
- SprintData Common 의 CRUDRepository + PagingAndSortingRepository 이 쿼리기능을 제공
사용 방법
returnType {접두어}{도입부}By{프로퍼티 표현식}(조건식)[(And | Or){프로퍼티 표현식}(조건식)](OrderBy{프로퍼티}Asc | Desc) (매개변수...)
- | 표현식 |
---|
접두어 | Find, Get, Query, Count, ... |
도입부 | Distinct, First(N), Top(N) |
프로퍼티 표현식 | Person.Address.ZipCode => find(Person)ByAddress_ZipCode(...) |
조건식 | IgnoreCase, Between, LessThan, GreaterThan, Like, Contains, ... |
정렬 조건 | `OrderBy{프로퍼티}Asc |
리턴 타입 | E, Optional<E>, List<E>, Page<E>, Slice<E>, Stream<E> |
매개변수 | Pageable, Sort |
List<User> findByNameAndPassword(String name, String password);
List<User> findDistinctUserByNameOrPassword(String name, String password);
List<User> findUserDistinctByNameOrPassword(String name, String password);
List<User> findByNameIgnoreCase(String name);
List<User> findByNameAndPasswordAllIgnoreCase(String name, String password);
List<Person> findByNameOrderByNameAsc(String name);
List<Person> findByNameOrderByNameDesc(String name);
Page<User> findByName(String name, Pageable pageable);
Slice<User> findByName(String name, Pageable pageable);
List<User> findByName(String name, Sort sort);
List<User> findByName(String name, Pageable pageable);
Stream<User> readAllByNameNotNull();
:: QueryDSL
- QueryDSL의
Predicate
인터페이스로 조건문을 여러개를 구성하여 따로 관리 가능
findOne(Predicate)
, findAll(Predicate)
주로 이 2개 메소드 사용
findOne
= Optional<T>
리턴
findAll
= List<T>
| Page<T>
| Iterable<T>
| Slice<T>
리턴
- Type Safe 기능
- 조건문 구성시에 사용되는 객체, 필드 조건이 실제 타입과 일치한지 체크
- QueryDSL 의존성을 추가하면 SpringData에 의해
QueryDslPredicateExecutor
인터페이스가 추가된다.
QueryDslPredicateExecutor
는 Repository가 QueryDsl 을 실행할 수 있는 인터페이스를 제공하는 역할을 한다.
장점
- 문자가 아닌 코드로 쿼리를 작성함 -> 컴파일 시점에 문법 오류를 쉽게 확인 가능
- 자동 완성 등 IDE의 도움을 받을 수 있음
- 동적인 쿼리 작성이 편리
- 쿼리 작성 시 제약 조건 등을 메서드 추출을 통해 재사용 가능
Spring 3.X 버전
- 의존성만 추가하면 빌드에 자동으로 포함되서 실행
implementation 'com.querydsl:querydsl-jpa:5.0.0:jakarta'
annotationProcessor "com.querydsl:querydsl-apt:${dependencyManagement.importedProperties['querydsl.version']}:jakarta"
annotationProcessor "jakarta.annotation:jakarta.annotation-api"
annotationProcessor "jakarta.persistence:jakarta.persistence-api"
Spring 2.X 버전
- QueryDSL 빌드 Task 를 따로 설정
- queryDSL 의존성, 소스 디렉토리 설정, annotation 프로세서 설정, Task 정의
plugins {
...
id "com.ewerk.gradle.plugins.querydsl" version "1.0.10"
}
compileQuerydsl{
options.annotationProcessorPath = configurations.querydsl
}
configurations {
...
querydsl.extendsFrom compileClasspath
}
def querydslSrcDir = 'src/querydsl/generated'
querydsl {
library = "com.querydsl:querydsl-apt"
jpa = true
querydslSourcesDir = querydslSrcDir
}
sourceSets {
main {
java {
srcDirs = ['src/main/java', querydslSrcDir]
}
}
}
project.afterEvaluate {
project.tasks.compileQuerydsl.options.compilerArgs = [
"-proc:only",
"-processor", project.querydsl.processors() +
',lombok.launch.AnnotationProcessorHider$AnnotationProcessor'
]
}
dependencies {
implementation("com.querydsl:querydsl-jpa")
implementation("com.querydsl:querydsl-apt")
...
}
:: QueryDSL gradle 빌드 스크립트 원리
- Gradle 빌드시에 QueryDSL은 프로젝트 내의
@Entity
어노테이션을 선언한 클래스를 탐색하고, JPAAnnotationProcessor
를 사용해 Q클래스를 생성한다.
querydsl-apt
가 @Entity
및 @Id
등의 매핑정보 Annotation을 알 수 있도록, javax.persistence
과 javax.annotation
을 annotationProcessor에 함께 추가한다.
annotationProcessor
는 Java 컴파일러 플러그인으로, 컴파일 단계에서 어노테이션을 분석 및 처리함으로써 추가적인 파일을 생성한다.
- 개발 환경에서 생성된 Q클래스를 인지할 수 있도록 /build/generated 디렉토리를 프로젝트의 sourceSet에 추가
- 이렇게 되면 IDE 에서도 생성된 Q클래스 파일을 인식하여 개발할 수 있게 된다.
QueryDSL 실습을 위해서는 Repository에 QuerydslPredicateExecutor<Channel>
의존성 추가 해야 한다.
:: QuerydslPredicateExecutor 활용
- QuerydslPredicateExecutor 로는 Join 연산이 불가능하여 구현 불가능 -> 단점
- 멤버 컬렉션까지만 조회 가능하며 이것을 묵시적 조인(1 Depth 자동 조인) 이라고 한다.
- 즉, channel 의 threads 까지만 접근 가능한것이 묵시적 조인
- 반면에, Join 연산이 수행되는건 명시적 조인 이라고 한다. (2 Depth 이상 조인)
- Join 없이 조건이 많이 추가될수록 QuerydslPredicateExecutor 활용 가능하다.
- 실무에서는 Join이 많이 발생하기 때문에 JPAQueryFactory 가 주로 쓰임
- Join이 필요하다면 JPQL 과 JPAQueryFactory 로 하면 됨