스프링데이터 + JPA/QueryDSL

0. 프리뷰

sdafdq 2023. 11. 17. 12:14

QueryDSL은 JPQL을 자바 코드로 작성할 수 있게끔 도와주는 오픈소스 라이브러리

 

JPQL을 자바 코드로 작성하게끔 지원해 주는 건 이것 말고도 여러가지 있긴 한데,

이거는 정말 코드가 직관적이다.

JPQL과 거의 유사해서 해석도 쉽다.

 

쿼리 dsl 쓰려면 우선,

설정을 해 줘야 하는데 이거는 스프링 부트 버전마다 다르다.

https://lordofkangs.tistory.com/461

 

[QueryDSL] QueryDSL 설정하기 ( SpringBoot 2.6이상, SpringBoot 3.x )

QueryDSL 설정은 쉽지않다. 인프런 김영한 강사님의 QueryDSL 강의를 수강하고 있는 학생이라면 QueryDSL 설정에 어려움을 겪고 있을 것이라 예상된다. 아무래도 강사님이 사용하는 버전이 SpringBoot 2.2.2

lordofkangs.tistory.com

그냥 검색하면 나온다.

 

def querydslSrcDir = 'src/main/generated'
clean {
	delete file(querydslSrcDir)
}
tasks.withType(JavaCompile) {
	options.generatedSourceOutputDirectory = file(querydslSrcDir)
}

여기 이 부분은 그렇게 설정해서 만든 Q(QueryDSL 자바 파일)파일을 어디다 위치시킬건지

 

여튼 이렇게 해 놓으면,

Gradle 창에서

Tasks -> other -> compileJava 하면 (외부 라이브러리 이니 other인듯)

 

명시해놓은 저 위치에 Q파일들이 생성됨.

도메인 별로 생김.

 

이제, 리포지토리에서 그걸 이용하면 됨.

public List<Order> findAll(OrderSearch orderSearch){
    QOrder order = QOrder.order;
    QMember member = QMember.member;

    JPAQueryFactory query = new JPAQueryFactory(em);

    return query.select(order)
            .from(order)
            .join(order.member, member)
            .where(statusEq(orderSearch.getOrderStatus()), nameLike(orderSearch.getMemberName()))
            .limit(1000)
            .fetch();
}

private BooleanExpression statusEq(OrderStatus statusCond){
    if(statusCond == null){
        return null;
    }
    return QOrder.order.status.eq(statusCond);
}

private BooleanExpression nameLike(String memberName){
    if(!StringUtils.hasText(memberName)){
        return null;
    }

    return QMember.member.name.contains(memberName);
}

 

QOrder가 order에 대한 queryDSL용 정보라고 보면 됨.

 

queryDSL을 쓰면은 JPAQueryFactory, 즉 쿼리 공장이 있어야 함.

거기에 엔티티매니저를 넣어서 커넥션과 연동되게끔.

 

이제 그냥 jpql 짜듯이? 하면 됨.

select(가져올엔티티).from(근원).join(근원의뭐를조인할열쇠로삼을지, 조인할근원)

.where(조건,조건)

여기 이 조건 부분이 이제 핵심.

아래 보면 Boolean표현식을 반환토록 함. 저거 QueryDSL꺼임.

저렇게 만약 null이면 그냥 null을 반환하고, (그러면 where에서 null이면 그냥 무시함.)

뭔가 있으면 QOrder의 order의 status와 eq(인자), 즉 같은지 비교하는 쿼리를 만듦. 

 

또 name도,

먼저 문자열 자체가 뭔가 있는지 확인해보고 텍스트가 없으면 null,

있으면 member근원의 name에 저 memberName을 contains 하고 있는 것,

쿼리로 따지면

m.name like '%:memberName%'

이런 식으로 짜 질듯.

저게 BooleanExpression에 담겨서 감.

그럼 where()에서 보고 null이면 거짓? 으로 하지 않고, 값이 있으면 where ~~ 하는 듯.

where()도 내부적으로 인자들이 모두 null이면 where조차 생성하지 않고, 또 and같은 것도 인자가 여러개가 참이면(null이 아니면) 알아서 붙여줄 거임. 그 정도는 구현하기 쉬움.

 

여튼 .limit(1000) 최대 1000개까지, 하고

fetch() 해서 끌어옴.

 

    select
        o1_0.order_id,
        o1_0.delivery_id,
        o1_0.member_id,
        o1_0.order_date,
        o1_0.status 
    from
        orders o1_0 
    join
        member m1_0 
            on m1_0.member_id=o1_0.member_id 
    where
        o1_0.status=? 
        and m1_0.name like ? escape '!' 
    fetch
        first ? rows only
2023-11-17T12:00:48.310+09:00  INFO 13116 --- [nio-8080-exec-2] p6spy                                    : #1700190048310 | took 0ms | statement | connection 29| url jdbc:h2:tcp://localhost/./jpashop
select o1_0.order_id,o1_0.delivery_id,o1_0.member_id,o1_0.order_date,o1_0.status from orders o1_0 join member m1_0 on m1_0.member_id=o1_0.member_id where o1_0.status='CANCEL' and m1_0.name like '%user%' escape '!' fetch first 1000 rows only;

일단은 order 쿼리 날라간 부분만 가져옴.

where 부분을 보셈. 둘다 비우지 않고 옵션을 준 경우임.

null이거나 비어있으면 그냥 안붙음. 둘다 옵션 없는 경우 where 자체가 없음. where()에서 다 처리함.

 

 

 

 

Q파일들, 그러니까 generated 된 것들은 build 타임에 생성되는거라 깃허브에 올릴 필요 없음. 빼주셈. 깃허브에 올릴 때

 

limit 꼭 붙일 필요는 없다고 chat GPT가 그럼. 여튼 제대로 배우기 시작하면 알게 될거임.

 

 

그리고, 우리가 new 오퍼레이션 쓰면서 Dto로 직접받는 거 할 때, 패키지 경로까지 다 명시해 줬었어야 했는데,

QueryDSL을 쓰면 패키지명도 안써도 되고 생성자도 사용가능하고 setter도 사용가능하다고 한다.

자세한 건 나중에..

 

 

그리고, 꼭 동적 쿼리가 아니라 정적 쿼리인 경우에도 QueryDSL을 사용하면 이점이 있다.

직관적이고

컴파일 시점에 문법 오류 발견하고

코드 자동완성

코드 재사용

Dto 정말 간편하게 지원 등

 

나는 직관적인건 JPQL이 더 직관적이고 문법 오류도 사실 인텔리제이가 jpql? sql도 그런가? 여튼 문자열인데도 문법오류를 잡아주는 듯 하다.

 

자동완성이 정말 편리할 듯.

 

근데 일단 SQL, 그 후 JPQL에 익숙해 져야 함.

또, Dto는 그냥 QueryDSL로 받는 게 좋을 듯.

JPQL이 할 수 있는 건 거의 다 지원해 준다고 한다.

 

또 재사용성.

확실히 인자로 받아서 그냥 넣어주면 될 것 같다.

 

즉, 조립이 쉽다.

 

 

 

'스프링데이터 + JPA > QueryDSL' 카테고리의 다른 글

5. H2 DB 설치 및 설정  (0) 2023.11.27
4. 연관 라이브러리  (0) 2023.11.27
3. QueryDSL 설정  (0) 2023.11.27
2. 프로젝트 생성  (0) 2023.11.27
1. 소개  (0) 2023.11.27