우당탕탕

Spring Boot에서 Querydsl 도입 직접 해본 후 궁금한 점 8가지 Q&A 본문

Tech/Spring

Spring Boot에서 Querydsl 도입 직접 해본 후 궁금한 점 8가지 Q&A

모찌모찝 2026. 7. 21. 10:47

Spring Boot 프로젝트에 Querydsl을 도입하다 보니 생각보다 삽질을 많이 했어요. 공식 문서만 보면 간단할 것 같은데, 실제로는 환경 설정부터 코드 작성, 빌드 문제까지 헷갈리는 부분이 한두 가지가 아니더라고요.

그래서 제가 직접 부딪히면서 해결한 경험을 토대로, Spring Boot에서 Querydsl 도입할 때 독자분들이 가장 많이 검색하는 질문 8개를 모아 꼼꼼히 답해봤어요. 이 글 하나만 읽으면 Querydsl 도입과 활용에 관한 걱정은 다 덜 수 있을 거예요.

개발 환경 / 버전 정보

제가 사용한 환경은 Java 17, Spring Boot 3.1.4, 그리고 Querydsl 5.0.0 입니다. Maven을 빌드 도구로 사용했고, JPA는 Hibernate 기반이었어요.

Spring Boot에서 Querydsl 도입 직접 해본 후기 관련 이미지

Spring Boot에서 Querydsl 도입 직접 해본 후기 관련 정보

Q1. Querydsl 설정, gradle/maven 어디서 막히나요?

사실 이 부분이 가장 기본인데도 많이들 헷갈려하시는 것 같더라고요. 저는 처음에 Maven 설정을 제대로 안 해서 Q-class 생성이 안 됐어요. Querydsl은 JPA 엔티티 기준으로 Q클래스를 생성하는데, 이걸 빌드 과정에서 자동으로 만들어줘야 하거든요.

Maven 기준 핵심 설정은 pom.xml에 다음 플러그인과 의존성 추가예요.

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

<dependency>
  <groupId>com.querydsl</groupId>
  <artifactId>querydsl-apt</artifactId>
  <version>5.0.0</version>
  <scope>provided</scope>
</dependency>

<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/java</outputDirectory>
        <processor>com.querydsl.apt.jpa.JPAAnnotationProcessor</processor>
      </configuration>
    </execution>
  </executions>
</plugin>

이걸 안 하면 Q클래스가 만들어지지 않고, IDE에서 import 오류가 발생해요. 또 빌드 시에 target/generated-sources/java 경로를 소스 폴더로 추가해줘야 Q클래스가 인식됩니다.

Q2. Q클래스가 안 만들어져요, 왜 그럴까요?

처음 도입할 때 제가 가장 오래 걸렸던 부분인데요. Q클래스 생성 문제는 크게 두 가지 이유가 있어요.

  • JPA 어노테이션이 정상적으로 붙어있지 않음 (예: @Entity 누락)
  • 빌드 플러그인 설정 오류 또는 적용 안 됨

제 경험으로는 JPA 엔티티에 @Entity 어노테이션이 꼭 붙어있어야 Q클래스가 만들어지고, build 시에 mvn clean compile 명령을 통해 플러그인이 실행되는지 확인해야 해요.

Spring Boot에서 Querydsl 도입 직접 해본 후기 직접 정리한 자료

Spring Boot에서 Querydsl 도입 직접 해본 후기 관련 정보

Q3. Querydsl 기본 문법, 이렇게 사용하면 됩니다

Querydsl을 처음 도입하면 JPQL에 익숙한 분들은 API 사용법이 생소할 수 있어요. 저는 이렇게 사용했는데 도움이 될 것 같아요.

// JPAQueryFactory를 주입
@Autowired
private JPAQueryFactory queryFactory;

// QUser는 자동 생성된 Q클래스
QUser user = QUser.user;

// 간단한 조회
List<User> users = queryFactory.selectFrom(user)
  .where(user.age.gt(20)) // 20살 이상 조회
  .orderBy(user.name.asc())
  .fetch();

이 코드 구조가 쿼리를 타입 안정성 있게 작성할 수 있어서, 실수하기 어렵고 IDE 자동완성도 좋아서 저는 너무 편했어요.

Q4. JPAQueryFactory 주입 안 되면 어떻게 하나요?

이 부분도 많이들 헷갈리는데, 저는 Spring 빈으로 직접 등록했어요. 그냥 @Bean 하나 만들면 됩니다.

@Configuration
public class QuerydslConfig {

  @PersistenceContext
  private EntityManager em;

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

이렇게 등록해두면 다른 곳에서 편하게 @Autowired나 생성자 주입으로 쓸 수 있더라고요.

Spring Boot에서 Querydsl 도입 직접 해본 후기 참고 사진

Spring Boot에서 Querydsl 도입 직접 해본 후기 관련 정보

Q5. 복잡한 join / 서브쿼리는 어떻게 처리해요?

Querydsl의 강점 중 하나인데, 저도 처음엔 서브쿼리 문법이 익숙하지 않았어요. 이런 식으로 하면 됩니다.

// QUser, QOrder는 각각 엔티티에 대응
QUser user = QUser.user;
QOrder order = QOrder.order;

List<User> result = queryFactory.selectFrom(user)
  .where(user.id.in(
    JPAExpressions.select(order.user.id)
      .from(order)
      .where(order.status.eq("DELIVERED"))
  ))
  .fetch();

서브쿼리는 JPAExpressions 클래스를 쓰고, join도 자연스럽게 메서드 체인으로 연결할 수 있어서 편했어요.

Q6. Querydsl 빌드 후 IDE에서 오류나면 어떻게 해결하나요?

저도 Q클래스는 빌드할 때 만들어지는데 IDE가 인식을 못 하는 문제가 있었어요. 보통 target/generated-sources/java 폴더를 소스 루트로 잡아주면 해결되는데, IntelliJ 기준으로 설명할게요.

우선 File -> Project Structure -> Modules -> Sources 메뉴에서 위 경로를 Sources 폴더로 지정해주면 돼요. 그래도 안 되면 캐시 무효화(File -> Invalidate Caches / Restart)를 했더니 해결됐어요.

Q7. Querydsl과 JPARepository / Spring Data는 어떻게 같이 쓰나요?

많은 분들이 궁금해하는 부분인데, 저도 처음에 혼동이 많았어요. 보통은 기존 JpaRepository를 그대로 두고, 복잡한 쿼리만 Querydsl로 처리하는 경우가 많더라고요.

저는 직접 리포지터리에 커스텀 인터페이스를 만들고, 구현체에서 Querydsl로 쿼리를 짰어요.

// 커스텀 인터페이스
public interface UserRepositoryCustom {
  List<User> findUsersByCustomQuery(String namePart);
}

// 구현체
public class UserRepositoryImpl implements UserRepositoryCustom {

  private final JPAQueryFactory queryFactory;

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

  @Override
  public List<User> findUsersByCustomQuery(String namePart) {
    QUser user = QUser.user;
    return queryFactory.selectFrom(user)
          .where(user.name.containsIgnoreCase(namePart))
          .fetch();
  }
}

// JpaRepository에 인터페이스 상속
public interface UserRepository extends JpaRepository<User, Long>, UserRepositoryCustom {
}

이렇게 하면 보통 CRUD는 JpaRepository가 담당하고, 복잡한 검색 로직만 Querydsl로 처리해서 효율적이에요.

Q8. Querydsl 사용 시 성능 문제나 주의할 점은?

마지막으로 제가 경험한 성능 관련 팁인데요, Querydsl은 쿼리 자체는 JPQL 기반이라 JPA와 큰 차이는 없어요. 다만 너무 복잡한 조건을 한 번에 처리하면 쿼리가 길어지고, DB 인덱스와 맞지 않으면 느려질 수 있더라고요.

그래서 저는 쿼리 최적화 차원에서 조건절을 잘 분리하고, 필요한 페치 조인만 사용했어요. 또 Querydsl 결과를 페이지네이션할 땐 fetchResults() 대신 fetch() + 별도 count 쿼리를 돌려서 성능을 좀 더 미세조정했습니다.

그리고 무엇보다도 Querydsl은 타입 안전성을 최대 장점으로 활용하는 게 가장 좋은 전략이라고 생각해요. 문자열로 된 JPQL 쿼리를 줄이고, 컴파일 시점에 실수를 미리 잡으니 코드 유지보수가 훨씬 편해졌거든요.

Querydsl 도입하면서 겪은 어려움과 FAQ를 중심으로 정리해봤는데, 여러분도 써보시면 확실히 쿼리 작성이 한결 수월해질 거예요. 저도 처음엔 헷갈리고 막혔지만, 한 번 익히면 진짜 편리해서 추천합니다!

Comments