담비의 개발블로그

[DB]JPA - QueryDSL란 본문

DataBase

[DB]JPA - QueryDSL란

담비12 2024. 9. 5. 19:08
QueryDSL

 

Java에서 타입 안전한 방식으로 동적 SQL 쿼리를 작성하고 실행할 수 있도록 도와주는 프레임워크이다. JPA와 함께 사용하여 복잡한 쿼리를 더 직관적이고 안전하게 작성할 수 있게 해주는 도구이다.

 

 

◆ QueryDSL의 특징

1. 타입 안전한 쿼리 작성: QueryDSL은 자바 코드로 SQL이나 JPQL 쿼리를 작성할 때, 컴파일 시점에서 오류를 감지할 수 있는 타입 안전성을 제공한다. 즉, 잘못된 쿼리 작성 시 컴파일러가 오류를 잡아주어, 런타임 시 발생할 수 있는 SQL 오류를 미리 방지할 수 있다.

2. 동적 쿼리 지원: QueryDSL은 조건에 따라 동적으로 쿼리를 작성할 수 있다. 조건이 여러 개일 때, 코드에서 이를 쉽게 조합하고 관리할 수 있다.

3. 기존 JPQL, Criteria API보다 더 직관적: QueryDSL은 JPA의 표준 동적 쿼리 작성 방식인 Criteria API보다 훨씬 더 간결하고 직관적인 문법을 제공한다. Criteria API는 복잡한 구문과 길이가 길어지는 단점이 있는데, QueryDSL은 이를 해결하여 더 간결하게 쿼리를 작성할 수 있게 한다.

4. 쿼리 빌더 스타일의 문법: 쿼리를 마치 메서드 호출을 하듯이 작성할 수 있습니다. 쿼리의 가독성을 높이고, 간결한 코드로 복잡한 쿼리를 작성할 수 있다.

 

 

 

QueryDSL 설정

 

가장중요한 설정!

 

gradle 설정 방법

plugins {
    id "com.ewerk.gradle.plugins.querydsl" version "1.0.10"
}

dependencies {
    implementation "com.querydsl:querydsl-jpa"
    annotationProcessor "com.querydsl:querydsl-apt:${dependencyManagement.importedProperties['querydsl.version']}:jpa"
}

querydsl {
    jpa = true
    querydslSourcesDir = "src/main/generated"  // Q 클래스가 생성될 경로
}

 

 

 

mave 설정 방법

<dependency>
    <groupId>com.querydsl</groupId>
    <artifactId>querydsl-jpa</artifactId>
</dependency>

<build>
    <plugins>
        <plugin>
            <groupId>com.mysema.maven</groupId>
            <artifactId>apt-maven-plugin</artifactId>
            <version>1.1.3</version>
            <executions>
                <execution>
                    <goals>
                        <goal>process</goal>
                    </goals>
                    <configuration>
                        <outputDirectory>target/generated-sources</outputDirectory>
                        <processor>com.querydsl.apt.jpa.JPAAnnotationProcessor</processor>
                    </configuration>
                </execution>
            </executions>
        </plugin>
    </plugins>
</build>

 

 

Q클래스가 지정될 곳을 설정해주지 않으면 기본적으로는 아래에서 생성된다.

Gradle: 기본적으로 build/generated 아래에 Q 클래스가 생성될 수 있다.
Maven: 기본적으로 target/generated-sources에 생성된다.

Spring Boot에서 QueryDSL 사용 방식

 

1. JPAQueryFactory 빈 등록
JPAQueryFactory는 QueryDSL의 핵심 클래스 중 하나로, 쿼리 작성과 실행을 담당한다. 이를 Spring에서 빈으로 관리하고 주입받아 사용할 수 있다.

import com.querydsl.jpa.impl.JPAQueryFactory;
import jakarta.persistence.EntityManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class QuerydslConfig {

    private final EntityManager entityManager;

    public QuerydslConfig(EntityManager entityManager) {
        this.entityManager = entityManager;
    }

    @Bean
    public JPAQueryFactory jpaQueryFactory() {
        return new JPAQueryFactory(entityManager);
    }
}

 

 

2. JPAQueryFactory 사용
위에서 설정한 JPAQueryFactory를 주입받아 원하는 서비스나 리포지토리에서 QueryDSL 쿼리를 작성할 수 있다. 예를 들어, 아래와 같이 서비스 계층에서 사용할 수 있다. JPAQueryFactory를 주입받아 QueryDSL을 사용하여 username과 age에 따라 멤버를 조회하는 쿼리를 실행한다.

import com.querydsl.jpa.impl.JPAQueryFactory;
import com.querydsl.core.types.dsl.BooleanExpression;
import org.springframework.stereotype.Service;
import org.springframework.beans.factory.annotation.Autowired;

@Service
public class MemberService {

    private final JPAQueryFactory queryFactory;

    @Autowired
    public MemberService(JPAQueryFactory queryFactory) {
        this.queryFactory = queryFactory;
    }

    public List<Member> findMembersByUsernameAndAge(String username, int age) {
        QMember member = QMember.member;

        return queryFactory
            .selectFrom(member)
            .where(member.username.eq(username), member.age.gt(age))
            .fetch();
    }
}

 

 

3. Spring Data JPA와 QueryDSL 함께 사용
Spring Data JPA와 QueryDSL을 함께 사용하려면 리포지토리에 QueryDSL 기능을 추가할 수 있다. Spring Data JPA의 리포지토리 인터페이스를 확장하여 QueryDSL을 사용할 수 있게 설정하는 방법도 있다.

3.1. 리포지토리 설정
Spring Data JPA 리포지토리에 QueryDSL을 통합하려면 커스텀 리포지토리 인터페이스를 만들어서 이를 구현해야 한다.

 

// 리포지토리 인터페이스
import com.querydsl.core.types.Predicate;
import com.neo.entity.Member;

import java.util.List;

public interface MemberRepositoryCustom {
    List<Member> findMembersByPredicate(Predicate predicate);
}

 

// 리포지토리 구현 클래스
import com.querydsl.jpa.impl.JPAQueryFactory;
import com.querydsl.core.types.Predicate;
import com.neo.entity.Member;
import com.neo.entity.QMember;
import org.springframework.stereotype.Repository;
import java.util.List;

@Repository
public class MemberRepositoryImpl implements MemberRepositoryCustom {

    private final JPAQueryFactory queryFactory;

    public MemberRepositoryImpl(JPAQueryFactory queryFactory) {
        this.queryFactory = queryFactory;
    }

    @Override
    public List<Member> findMembersByPredicate(Predicate predicate) {
        QMember member = QMember.member;

        return queryFactory
            .selectFrom(member)
            .where(predicate)
            .fetch();
    }
}

 

// Spring Data JPA 리포지토리
import org.springframework.data.jpa.repository.JpaRepository;

public interface MemberRepository extends JpaRepository<Member, Long>, MemberRepositoryCustom {
}

 

위 예시에서는 MemberRepositoryCustom을 만들어 Predicate를 사용한 QueryDSL 쿼리 기능을 추가하였고, 이를 구현한 MemberRepositoryImpl 클래스에서 QueryDSL 쿼리를 실행한다.

 

 

3.2. Predicate를 이용한 동적 쿼리
QueryDSL은 Predicate를 이용해 조건을 동적으로 생성할 수 있다. 조건에 따라 다른 쿼리를 생성하거나 여러 조건을 조합할 수 있다. 이렇게 작성된 Predicate는 MemberRepository에서 동적 쿼리를 생성할 때 사용할 수 있다.

import com.querydsl.core.types.dsl.BooleanExpression;

public class MemberPredicate {

    public static BooleanExpression hasUsername(String username) {
        if (username == null || username.isEmpty()) {
            return null;
        }
        return QMember.member.username.eq(username);
    }

    public static BooleanExpression hasAgeGreaterThan(int age) {
        return QMember.member.age.gt(age);
    }
}

 

간단하게 정리하면, 
1. QueryDSL을 Spring Boot와 함께 사용하려면, JPAQueryFactory를 빈으로 등록해야 하며, 이를 서비스나 리포지토리에 주입받아 쿼리를 작성한다.
2. Spring Data JPA 리포지토리에서 QueryDSL을 사용하려면, 커스텀 리포지토리 인터페이스와 구현 클래스를 만들어 추가적인 QueryDSL 쿼리 기능을 구현할 수 있다.
3. QueryDSL의 동적 쿼리 기능을 활용하여 Predicate를 사용해 여러 조건을 조합하여 동적 쿼리를 작성할 수 있다.

'DataBase' 카테고리의 다른 글

PostgreSQL  (0) 2025.07.05
[DB]Persistence Context(영속성 컨텍스트)  (0) 2024.09.02
[DB]EntityManager(엔티티매니저)  (0) 2024.09.02
[DataBase]Hibernate란?  (0) 2024.08.09
[MariaDB]member테이블 관련 알아두면 좋을 내용  (0) 2024.06.20