Query Domain Specific Language의 약자로 오픈소스 프로젝트이며 JPQL을 JAVA코드로 작성할 수 있도록 해주는 라이브러리다.
즉, 기존 Query를 작성 시 SQL문법 규칙 대로 작성 해야하지만 그러지 않고 JAVA코드로만 작성할 수 있도록 도와주는 라이브러리로 생각하면 쉽다.
JPA를 사용하면 QueryMethod와 @Query를 통해 여러 기능을 만들 수 있지만 이는 고정된 값을 가진다는 단점이 있다.
쉽게 말해, 쇼핑몰을 예로 들자면 카테고리가 없고 상품만 있는 쇼핑몰에서는 충분히 사용 가능 하지만 카테고리가 대분류 소분류로 나누어 지고 이러한 카테고리가 3개 4개 라면 동적으로 쿼리를 생성해서 처리할 수 있는 기능이 필요하다.
이러한 기능을 얻기 위해 우리는 QueryDsl을 사용한다.
즉, QueryDsl은 복잡한 검색조건이나 조인,서브 쿼리 등의 기능도 구현이 가능하다.
JPQL을 간단하게 집고 가자면 보통 Table을 대상으로 Query를 하지만 JPQL은 Entity를 대상으로 Query한다.
JPA에서 제공하는 메소드 호출만으로 섬세한 Query작성이 어렵다는 문제를 해소하기 위해 탄생됬다.
buildscript {
ext {
queryDslVersion = '5.0.0'
}
}
def querydslDir = "$buildDir/generated/querydsl"
querydsl {
jpa = true
querydslSourcesDir = querydslDir
}
sourceSets {
main.java.srcDir querydslDir
}
compileQuerydsl {
options.annotationProcessorPath = configurations.querydsl
}
configurations {
compileOnly {
extendsFrom annotationProcessor
}
querydsl.extendsFrom compileClasspath
}
implementation 'com.querydsl:querydsl-jpa'
QueryDsl에서는 엔티티로 설정된 클래스에 Q모델이라는 쿼리타입 클래스를 미리 생성해놓고 메타데이터로 사용하여 쿼리를 메소드 기반으로 작성합니다.
쉽게 말하자면 queryDsl 라이브러리를 사용하면서 쿼리문을 작성하려면 Q타입 클래스가 필요합니다.
public interface PostRepository extends JpaRepository<Post, Long> {
@Query("select p from Post p join fetch p.comments")
List<Post> findAllInnerFetchJoin();
@Query("select distinct p from Post p join fetch p.comments")
List<Post> findAllInnerFetchJoinWithDistinct();
}
위 코드는 우리가 지금까지 사용하던 정적쿼리 입니다.
@Configuration
public class QueryDslConfig {
@PersistenceContext
private EntityManager entityManager;
@Bean
public JPAQueryFactory jpaQueryFactory() {
return new JPAQueryFactory(entityManager);
}
}
``'
프로젝트에서 QueryDsl을 사용하기 위해 JPAQueryFactory를 Bean으로 등록
public interface PostCustomRepository {
List<Post> findAllInnerFetchJoin();
List<Post> findAllInnerFetchJoinWithDistinct();
}
@Repository
public class PostCustomRepositoryImpl implements PostCustomRepository {
private final JPAQueryFactory jpaQueryFactory;
public PostCustomRepositoryImpl(JPAQueryFactory jpaQueryFactory) {
this.jpaQueryFactory = jpaQueryFactory;
}
@Override
public List<Post> findAllInnerFetchJoin() {
return jpaQueryFactory.selectFrom(post)
.innerJoin(post.comments)
.fetchJoin()
.fetch();
}
@Override
public List<Post> findAllInnerFetchJoinWithDistinct() {
return jpaQueryFactory.selectFrom(post)
.distinct()
.innerJoin(post.comments)
.fetchJoin()
.fetch();
}
}