티스토리 뷰

0.  QueryDSL이란?

public interface ItemRepository extends JpaRepository<Item, Long> {
    @Query("select i from Item i where i.itemDetail like %:itemDetail% order by i.price desc")
    List<Item>  findByItemDetail(@Param("itemDetail")String itemDetail);
}

 

위의 코드와 같이 직접 Query문을 작성하게 되면 두 가지의 단점이 있습니다.

1. 문제가 발생하는 경우 런타임 시점에 알게 됩니다.

2. 하나하나 타이핑을 해야한다.. 

 

위의 예제는 비교적 짧지만 join이 들어간 경우 여러 줄로 작성해야 했는데 그 과정에서 띄어쓰기로 인해 작동이 안되는 경우를 겪었습니다.. 

 

 

이를 해결하기 위해 QueryDSL을 대신 사용하였습니다.

 

QueryDSL은 JPQL을 코드로 작성할 수 있도록 도와주는 빌더 API입니다.

 

장점으로는 

  1. 고정된 SQL문이 아닌 조건에 맞게 동적으로 쿼리를 생성할 수 있다.
  2. 비슷한 쿼리를 재사용할 수 있으며 제약 조건 조립 및 가독성을 향상시킬 수 있다.
  3. 문자열이 아닌 자바 소스코드로 작성하기 때문에 컴파일 시점에 오류를 발견할 수 있다.
  4. IDE의 도움을 받아서 자동 완성 기능을 이용할 수 있기 때문에 생산성을 향상시킬 수 있다.

 

이제부터 QueryDSL을 적용해보겠습니다.

 

1. QueryDSL 적용하기

build.gradle
buildscript{
	ext{
		queryDslVersion="5.0.0"
	}
}

plugins {
	id 'java'
	id 'org.springframework.boot' version '2.7.6'
	id 'io.spring.dependency-management' version '1.1.0'
	id "com.ewerk.gradle.plugins.querydsl" version "1.0.10"
}

group = 'com.example'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '17'

configurations {
	compileOnly {
		extendsFrom annotationProcessor
	}
}

repositories {
	mavenCentral()
}

dependencies {
	...
    
	implementation "com.querydsl:querydsl-jpa:${queryDslVersion}"
	implementation "com.querydsl:querydsl-apt:${queryDslVersion}"
	
}

def querydslDir = "$buildDir/generated/querydsl"

querydsl {
	jpa = true
	querydslSourcesDir = querydslDir
}

sourceSets {
	main.java.srcDir querydslDir
}

compileQuerydsl{
	options.annotationProcessorPath = configurations.querydsl
}

configurations {
	compileOnly {
		extendsFrom annotationProcessor
	}
	querydsl.extendsFrom compileClasspath
}

test {
	useJUnitPlatform()
}

위의 코드와 같이 작성하여 QueryDSL을 추가합니다.

 

 

우측 Gradle -> other -> compileJava를 눌러 실행하게 합니다.

 

이 과정을 통해 entity로 등록한 클래스의 앞에 Q가 붙은 형태로 만들어진 것을 확인할 수 있습니다.

 

2. QueryDSL로 대체하기

ItemRepositoryCustom
public interface ItemRepositoryCustom {
    List<Item> findByItemDetail(@Param("itemDetail")String itemDetail);
}

XXXRepositoryCustom이란 이름으로 인터페이스를 생성합니다.

저의 경우 기존의 ItemRepository에서 Query로 작성한 함수들을 여기에 선언하였습니다.

 

ItemRepositoryCustomImpl
public class ItemRepositoryCustomImpl implements ItemRepositoryCustom {

    private JPAQueryFactory queryFactory;

    public ItemRepositoryCustomImpl(EntityManager entityManager) {
        this.queryFactory = new JPAQueryFactory(entityManager);
    }

    public List<Item> findByItemDetail(@Param("itemDetail")String itemDetail){
        List<Item> result=queryFactory.selectFrom(QItem.item)
                .where(QItem.item.itemDetail.contains(itemDetail))
                .orderBy(QItem.item.price.desc())
                .fetch();

        return result;
    }
}

위의 인터페이스를 구현한 클래스로 XXXRepositoryCustomImpl이란 클래스를 만들었습니다.

이 클래스 안에서 QueryDSL을 이용합니다. 

 

차이점은 Item이 아닌 QItem.item으로 사용하면 되는 부분입니다.

기존의  SQL과 큰 차이가 없어 쉽게 적용할 수 있습니다.

 

    private JPAQueryFactory queryFactory;

    public ItemRepositoryCustomImpl(EntityManager entityManager) {
        this.queryFactory = new JPAQueryFactory(entityManager);
    }

동적으로 쿼리를 생성하기 위해 JPAQueryFactory를 사용합니다.

생성자로 EntityManager를 넣어줍니다.                                                                                                                                                                                                                                                                                                                          

 

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

이제 기존의 ItemRepository에 있는 함수를 제거하고 ItemRepositoryCustom을 추가하면 됩니다.

 

 

공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2025/04   »
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
글 보관함