[Spring DB 2편] 7. QueryDSL

HJ·2023년 2월 5일
0

Spring DB 2편

목록 보기
7/11
post-thumbnail
post-custom-banner

김영한 님의 스프링 DB 2편 - 데이터 접근 활용 기술 강의를 보고 작성한 내용입니다.
https://www.inflearn.com/course/%EC%8A%A4%ED%94%84%EB%A7%81-db-2/dashboard


1. QueryDSL 소개

1-1. 기존 방식의 문제점

  • "select * from item" + "where ..." 처럼 + 로 합치는데 공백이 없으면 오류 발생

  • Query는 문자이기 때문에 Type-check 불가능, 실행하기 전까지 작동 여부 확인 불가능


1-2. QueryDSL

  • DSL = Domain( 도메인 ) Specific( 특화 ) Language( 언어 )

    • 특정한 도메인에 초점을 맞춘 제한적인 표현력을 가진 컴퓨터 프로그래밍 언어
  • QueryDSL : 쿼리에 특화된 프로그래밍 언어

  • QueryDSL은 쿼리를 자바로 type-safe 하게 개발할 수 있도록 지원하는 프레임워크

  • 컴파일 시 에러 체크가 가능하고 주로 JPA 쿼리( JPQL )에 사용

  • 데이터 쿼리 기능을 추상화

  • QueryDSL로 작성하면 JPQL이 생성되고 SQL이 실행된다




2. QueryDSL 설정

2-1. build.gradle

implementation 'com.querydsl:querydsl-jpa'
annotationProcessor "com.querydsl:querydsl-apt:${dependencyManagement.importedProperties['querydsl.version']}:jpa"
annotationProcessor "jakarta.annotation:jakarta.annotation-api"
annotationProcessor "jakarta.persistence:jakarta.persistence-api"


// Querydsl 추가, 자동 생성된 Q클래스 gradle clean으로 제거
clean {
delete file('src/main/generated')
}
  • gradle clean 명령어를 실행할 때 src/main/generated 의 파일도 함께 삭제해준다

  • 인텔리제이는 직접 삭제해야한다


2-2. Q 타입 생성 확인

  • 엔티티를 QueryDSL 에서 사용하기 위한 Q 타입을 생성해야한다

  • build 방식이 InetelliJ 인 경우

    • build ➜ Bjild Project 를 하면 src/main/generated 하위에 생성된다
  • build 방식이 gradle 인 경우

    • Gradle ➜ Tasks ➜ build ➜ clean : gradle 설정 초기화 ( build 폴더가 삭제됨 )

    • Gradle ➜ Tasks ➜ other ➜ compileJava : Q 타입 생성

    • build ➜ generated ➜ sources ➜ annotationProcessor ➜ java/main 하위에 Q 타입이 생성된다




3. QueryDSL 사용하기

3-1. JPAQueryFactory

public class JpaItemRepositoryV3 implements ItemRepository {

    private final EntityManager em;
    private final JPAQueryFactory query;

    public JpaItemRepositoryV3(EntityManager em) {
        this.em = em;
        this.query = new JPAQueryFactory(em);
    }
    ...
}
  • Querydsl을 사용하려면 JPAQueryFactory 가 필요

  • JPAQueryFactory 는 JPA 쿼리인 JPQL을 만들어주는 빌더 역할을 하기 때문에 EntityManager가 필요


3-2. Q 타입 사용

QItem item = QItem.item;

List<Item> result = query
        .select(item)
        .from(item)
        .where(builder)
        .fetch();
  • QItem item = new QItem("i"); 으로 사용한다

  • QItem 내부에 QItem.item 이 있기 때문에 QItem을 static import 해서 item 으로 사용할 수 있다

  • 코드에서 사용한 방식은 위의 2개를 합친 방식 ( QItem 선언 + QItem.item )


3-3. 동적 쿼리 사용

BooleanBuilder builder = new BooleanBuilder();

if (StringUtils.hasText(itemName)) {
    builder.and(item.itemName.like("%" + itemName + "%"));
}
if (maxPrice != null) {
    builder.and(item.price.loe(maxPrice));
}

List<Item> result = query
        .select(item)
        .from(item)
        .where(builder)
        .fetch();
  • BooleanBuilder 를 사용해서 원하는 where 조건들을 넣어주면 된다

3-4. 동적 쿼리 리펙터링

public List<Item> findAll(ItemSearchCond cond) {

    String itemName = cond.getItemName();
    Integer maxPrice = cond.getMaxPrice();

    QItem item = QItem.item;
        
    return query
            .select(item)
            .from(item)
            .where(likeItemName(itemName), maxPrice(maxPrice))
            .fetch();
}


private BooleanExpression likeItemName(String itemName) {
    if (StringUtils.hasText(itemName)) {
        return item.itemName.like("%" + itemName + "%");
    }
    return null;
}

private BooleanExpression maxPrice(Integer maxPrice) {
    if (maxPrice != null) {
        return item.price.loe(maxPrice);
    }
    return null;
}
  • where 에 조건을 직접 넣는 경우 AND 조건으로 처리된다

  • 다른 쿼리를 작성할 때 위의 두 조건 메서드를 재사용할 수 있다


3-5. 참고

  • QueryDSL 은 별도의 스프링 예외 추상화를 지원하지 않는다

  • 대신 @Repository 에서 스프링 예외 추상화를 처리해준다

  • 3-1번의 JpaItemRepositoryV3 는 JPA 방식을 사용 ( not SpringDataJPA )

    • 다음 게시글에서 수정 할 예정
post-custom-banner

0개의 댓글