스프링부트

JPA QueryDsl 사용하기

하이자바 2025. 5. 1. 20:27

QueryDsl이란 JPQL을 코드로 만들어주는 도구이다.

@Query와 같은 JPQL에서 까다로운 조건이 들어가는 경우 사용하는 것이 좋다.

 

1. 의존성

implementation 'com.querydsl:querydsl-jpa:5.0.0:jakarta'
annotationProcessor 'com.querydsl:querydsl-apt:5.0.0:jakarta'
annotationProcessor "jakarta.persistence:jakarta.persistence-api"
annotationProcessor "jakarta.annotation:jakarta.annotation-api"

 

2. Q파일 생성

프로젝트 실행 시 다음 경로에 Q 엔티티들이 생성된다. QueryDsl에 사용

def generated = layout.buildDirectory.dir("generated/querydsl").get().asFile
sourceSets {
    main {
        java {
            srcDirs += [generated]
        }
    }
}
// Q 파일 자동 생성
tasks.withType(JavaCompile).configureEach {
    options.annotationProcessorGeneratedSourcesDirectory = file(generated)
}

tasks.register("compileQuerydsl", JavaCompile) {
    source = sourceSets.main.java
    classpath = configurations.annotationProcessor + sourceSets.main.compileClasspath
    destinationDirectory.set(file(generated))
}

2. 콘피규 추가

@Configuration
public class QuerydslConfig {
    @Bean
    public JPAQueryFactory jpaQueryFactory(
            EntityManager entityManager
    ) {
        return new JPAQueryFactory(entityManager);
    }
}

 

3. 인터페이스 추가

Todo라는 도메인이 있다고 가정한다. 이 인터페이스는 레자피터리가 상속 받으면 되고 다음과 같이 원하는 메소드를 정의한다.

public interface TodoRepoQueryDSL {
    public TodoResponse getTodo(long todoId);
}

 

4. 레파지터리를 상속받는 클래스를 만들어 다음과 같이 사용할 수 있다.

@RequiredArgsConstructor
public class TodoRepositoryImpl implements TodoRepoQueryDSL{
    private final JPAQueryFactory queryFactory;

    @Override
    public TodoResponse getTodo(long todoId) {
        /*
                Todo todo = todoRepository.findByIdWithUser(todoId)
                select * from todo t join user u on t.user_id = u.user_id where t.id = 1;
                .orElseThrow(() -> new InvalidRequestException("Todo not found"));
         */
        QTodo todo = QTodo.todo;
        QUser user = QUser.user;

        Todo res = queryFactory
                .selectFrom(todo)
                .join(todo.user, user).fetchJoin()
                .where(todo.id.eq(todoId))
                .fetchOne();

        return new TodoResponse(Objects.requireNonNull(res));
    }
}