vue + jpa project (9) - JPQL과 Query DSL의 비교 본문

프로그램/Vue.js

vue + jpa project (9) - JPQL과 Query DSL의 비교

반응형

우선 개발을 시작하기 전에 JPQL과 Query DSL의 차이점을 알아보고 넘어가자.

나 자신도 처음에는 JPQL과 Query DSL 둘 중에 어떤 것으로 진행 해야할지를 판단이 안섰다. 

 

그래서 JPQL 과 Query DSL 각각이 무엇이고 장단점이 뭔지를 우선 알아보도록 한다.

 

1. JPQL
JPQL은 JPA의 일부로 Query를 Table이 아닌  엔티티 기준으로 작성하는 객체지향 쿼리 언어이다.

JPQL은 객체를 기준으로 모든 것이 움직이기 때문에 개발할 때, Table에 매핑되는 객체가 반드시 존재해야 하며

검색할 때도 Table이 아닌 엔티티를 대상으로 검색해야 한다.

JPQL 특징
1. SQL을 추상화한 JPA의 객체지향 쿼리
2. Table이 아닌 Entity 객체를 대상으로 개발
3. Entity와 속성은 대소문자 구분 (PERSON <> person)
4. 별칭(alias) 사용 필수

 

JPQL을 구현하는 방식으로는 두 가지 방식이 있다.

 

A. EntityManager 활용

@Autowired
EntityManager em;

TypedQuery<Member> tq = em.createQuery("select m from Member m where m.userId = :userId and m.userName = :userName", Member.class);
tq.setParameter("userId", "hong@gmail.com");
tq.setParameter("userName", "Cho");

List<Member> memberList = tq.getResultList();
log.info("userId: " + memberList.get(0).getUserId());

B. repository interface 활용

public interface MemberRepository extends JpaRepository<Member, Long>{
   /*	변수 바인딩 ?순번 사용 맵핑 */
   @Query("select m from Member m where m.userId = ?1 and m.userName = ?2")
   Member findMember(String userId, String userName);
   
   /*	변수 바인딩 :이름 사용 맵핑 */
   @Query("select m from Member m where m.userId = :userId and m.userName = :userName")
   Member findMember2(@Param("userId") String userId, @Param("userName") String userName);
}

 

2. Query DSL
JPQL의 단점을 보완하기 위하여 나온 것이 이것이다.

query DSL 특징
1. 문자가 아닌 코드로 작성
2. Compile 단계에서 문법 오류를 확인 가능
3. 코드 자동 완성 기능 활용 가능
4. 동적 쿼리 구현 가능

querydsl로 변경하면 아래와 같이 BooleanExpression을 이용해서 매우 간단하고 직관적인 방식을 적용할 수 있다.

public List<Order> findAll(OrderSearch orderSearch) {
  
 QOrder order = QOrder.order;
 QMember member = QMember.member;
 
 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 order.status.eq(statusCond);
}
 
private BooleanExpression nameLike(String nameCond) {
    if(!StringUtils.hasText(nameCond) {
        return null;
    }
    return member.name.like(namecond);
}

쿼리를 잘 다루는 사람이라면 JPQL이 좀 더 효율적이라고 생각하겠지만 코딩 시점에서 오류를 찾기가 어렵고 실제로 

돌려봐야지만 오류를 파악할 수 있다는 단점이 있다. 아직은 나 자신이 쿼리에 익숙해서 그런지 모르겠으나 일단 

Query DSL 방식으로 진행하고, 복잡한 쿼리가 있는 경우에 어떤 것이 더 나은지를 확인해 볼 필요가 있겠다.

 

따라서 Query DSL을 사용하기 위하여 gradle 설정을 아래와 같이 수정한다.

//*** querydsl *** 로 감싼 부분을 기존 파일에 추가한다.

스프링부트 3.x와 그 미만인 경우는 조금 달라서 같이 기표했다.

dependencies {
    implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
    implementation 'org.springframework.boot:spring-boot-starter-web'
    implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'
    compileOnly 'org.projectlombok:lombok'
    developmentOnly 'org.springframework.boot:spring-boot-devtools'
    runtimeOnly 'org.mariadb.jdbc:mariadb-java-client'
    annotationProcessor 'org.projectlombok:lombok'
    testImplementation 'org.springframework.boot:spring-boot-starter-test'
    
    
    //* * * querydsl * * *
    // == 스프링 부트 3.0 이상 ==
    implementation 'com.querydsl:querydsl-core'
    implementation 'com.querydsl:querydsl-jpa:5.0.0:jakarta'
    annotationProcessor "com.querydsl:querydsl-apt:${dependencyManagement.importedProperties['querydsl.version']}:jakarta"
    
    // == 스프링 부트 3.0 미만 ==
    //implementation 'com.querydsl:querydsl-core'
    //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 * * *
}
//* * * querydsl * * *
def generated='src/main/generated'
sourceSets {
    main.java.srcDirs += [ generated ]
}

tasks.withType(JavaCompile) {
    options.annotationProcessorGeneratedSourcesDirectory = file(generated)
}

clean.doLast {
    file(generated).deleteDir()
}
//* * * querydsl * * *

refresh gradle project 로 갱신해보자. 

그리고 View 창 중에서 Gradle Task 창에서 clean 과 build를 수행하자. 

정상적으로 build를 수행하면 src/main/generated 폴더가 생성이 되고

QBoardEntity.java 파일이 생성된 것을 확인할 수 있다.

(처음엔 좀 느리게 뜨거나 다시 한번 해야 갱신이 될 수도 있다.)

 

일단 여기까지 되었다면 설정이 완료된 것이다.

반응형

프로그램/Vue.js Related Articles

MORE

Comments