티스토리 뷰

Spring

Spring Data JPA - QueryDSL 구현 하기

구티맨 2021. 10. 14. 12:47

목차

    QueryDSL 이란?

    QueryDSL은 비표준 오픈소스 프레임워크로 JPQL을 편하게 작성하도록 도와주는 빌더 클래스 모음 입니다.

     

    코드기반이고, 단순하여 가독성이 좋아 사용하기가 좋습니다.

     

    그리고 컴파일 시점에 오류 발견이 가능하고, 자동완성도 지원하여 실무에서 JPA 사용시 많이 사용되고 있는 프레임워크 입니다.

     

    대부분의 쿼리를 QueryDSL로 작성할 수 있지만 JPQL에서 지원하지 않는 쿼리는 QueryDSL에서 작성할 수 없습니다.

     

    예를 들어, UNION을 지원하지 않고 FROM 절에 서브쿼리를 지원하지 않습니다.

     

    그래서 간혹 JPQL로 간단하게 쿼리를 작성할 수 있는 부분을 QueryDSL로 추가 작업을 통해서 구현하기도 합니다.

    QueryDSL 구현

    Spring Data JPA에서 QueryDSL을 구현하는 방법을 보여드리겠습니다.

    의존성 추가

    <dependencies>
        <dependency>
            <groupId>com.querydsl</groupId>
            <artifactId>querydsl-apt</artifactId>
        </dependency>
        
        <dependency>
            <groupId>com.querydsl</groupId>
            <artifactId>querydsl-jpa</artifactId>
        </dependency>
    </dependencies>
    
    <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/java</outputDirectory>
                            <processor>com.querydsl.apt.jpa.JPAAnnotationProcessor</processor>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>

     

    코드를 작성하기 이전에, QueryDSL은 쿼리 전용 클래스(Q)를 만들어야 합니다.

     

    의존성을 추가해주고, 컴파일을 하면 com.querydsl.apt.jpa.JPAAnnotationProcessor 에서

     

    @Entity가 정의된 클래스를 스캔하여, 쿼리 전용 클래스(Q)를 생성합니다.

    querydsl-apt : 쿼리 전용 클래스(Q)를 생성 해주는 라이브러리
    querydsl-jpa : QueryDSL JPA 라이브러리

    컴파일 후, target/generated-sources/java 폴더에 가면 클래스명 앞에 Q가 붙은 전용 클래스들이 생성된 것을 확인할 수 있습니다.

    QueryDSL 코드 작성

    전용 클래스가 생성되었으면 이제 QueryDSL로 쿼리를 구현하는 2가지 방법에 대해 살펴 보겠습니다.

     

    QueryDslPredicateExecutor 또는 QueryDslRepositorySupport를 사용하여 QueryDSL을 구현할 수 있습니다.

    QueryDslPredicateExecutor

    public interface ItemRepository extends JpaRepository<Item, Long>, QueryDslPredicateExecutor<Item> {
    
    }

    Repository에 QueryDslPredicateExecutor를 상속합니다.

     

    QItem item = QItem.item;
    Iterable<Item> result = itemRepository.findAll(
    	item.name.contains("장난감").and(item.price.between(10000, 20000))
    );

    그리고 해당 Repository를 사용하는 곳에서 findOne(), findAll() 함수에 predicate를 인자로 넣어 쿼리를 수행할 수 있습니다.

     

    편리하게 사용 가능하나 join, fetch를 사용할 수 없습니다.( JPQL에서 이야기하는 묵시적 조인은 가능합니다 )

     

    QueryDLS 의 다양한 기능을 모두 사용하려면 JPAQuery를 직접 사용하거나

     

    Spring Data JPA가 제공하는 QueryDslRepositorySupport를 사용해야 합니다.

    QueryDslRepositorySupport

    Spring Data JPA가 제공하는 공통 인터페이스는 직접 구현할 수 없기 때문에

     

    사용자 정의 Repository를 만들어 QueryDslRepositorySupport를 사용합니다.

    public interface OrderRepositoryExtends {
    
        public List<Order> search(OrderSearch orderSearch);
    
    }
    
    public class OrderRepositoryImpl extends QueryDslRepositorySupport implements OrderRepositoryExtends {
    
        public OrderRepositoryImpl() {
            super(Order.class);
        }
    
        @Override
        public List<Order> search(OrderSearch orderSearch) {
    
            QOrder order = QOrder.order;
            QMember member = QMember.member;
    
            JPQLQuery query = from(order);
    
            if (StringUtils.hasText(orderSearch.getMemberName())) {
                query.leftJoin(order.member, member)
                        .where(member.name.contains(orderSearch.getMemberName()));
            }
    
            if (orderSearch.getOrderStatus() != null) {
                query.where(order.status.eq(orderSearch.getOrderStatus()));
            }
    
            return query.list(order);
        }
    }

    사용자 정의 Repository와 QueryDslRepositorySupport를 상속받아 QueryDSL을 작성합니다.

    public interface OrderRepository extends JpaRepository<Order, Long>, JpaSpecificationExecutor<Order>, OrderRepositoryExtends {
    
    }

    그리고, 사용자 정의 Repository와 JpaSpecificationExecutor를 쿼리를 추가할 Repository에 상속하면 됩니다.

    댓글
    공지사항
    최근에 올라온 글
    최근에 달린 댓글
    Total
    Today
    Yesterday
    링크
    «   2024/05   »
    1 2 3 4
    5 6 7 8 9 10 11
    12 13 14 15 16 17 18
    19 20 21 22 23 24 25
    26 27 28 29 30 31
    글 보관함