Spring/QueryDSL

JPQL vs Querydsl

느리지만 꾸준하게 2022. 4. 19. 22:56

Querydsl 기본문법을 보자.

// QuerydslBasicTest


// JPQL 먼저 작성
    @Test
    public void startJPQL() {
         // member1을 찾아라.
        Member findMember = em.createQuery("select m from Member m where m.username = :username", Member.class)
                .setParameter("username", "member1")
                .getSingleResult();

        assertThat(findMember.getUsername()).isEqualTo("member1");
    }

 

돌리면 쿼리가 잘 동작한다.

select
        member0_.id as id1_1_,
        member0_.age as age2_1_,
        member0_.team_id as team_id4_1_,
        member0_.username as username3_1_ 
    from
        member member0_ 
    where
        member0_.username=?

 

 

아래와 같이 startQuerydsl 작성하고 compileQuerydsl 돌려주면 QMember과 QTeam이 생긴다.

// QuerydslBasicTest

package study.querydsl.entity;


import com.querydsl.jpa.impl.JPAQueryFactory;
import org.aspectj.lang.annotation.Before;
import org.assertj.core.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.transaction.annotation.Transactional;

import javax.persistence.EntityManager;

import static org.assertj.core.api.Assertions.*;

@SpringBootTest
@Transactional
public class QuerydslBasicTest {

    @Autowired
    EntityManager em;

    // 각 테스트 실행전에 데이터를 세팅을 하고 들어간다.
    @BeforeEach
    public void before() {
        Team teamA = new Team("teamA");
        Team teamB = new Team("teamB");
        em.persist(teamA);
        em.persist(teamB);

        Member member1 = new Member("member1", 10, teamA);
        Member member2 = new Member("member2", 20, teamA);

        Member member3 = new Member("member3", 30, teamB);
        Member member4 = new Member("member4", 40, teamB);
        em.persist(member1);
        em.persist(member2);
        em.persist(member3);
        em.persist(member4);
    }

    // JPQL 먼저 작성
    @Test
    public void startJPQL() {
         // member1을 찾아라.
        String qlString =
                "select m from Member m " +
                "where m.username = :username";
        Member findMember = em.createQuery(qlString, Member.class)
                .setParameter("username", "member1")
                .getSingleResult();

        assertThat(findMember.getUsername()).isEqualTo("member1");
    }

    @Test
    public void startQuerydsl() {
        JPAQueryFactory queryFactory = new JPAQueryFactory(em);
    }
}

 

 

 

test에 startQuerydsl을 작성하고 실행해도 잘 동작되는 것을 볼 수 있다.

@Test
public void startQuerydsl() {
    JPAQueryFactory queryFactory = new JPAQueryFactory(em);
    // 어떤 Q 멤버인지 이름을 주는 것
    QMember m = new QMember("m");

    Member findMember = queryFactory
            .select(m)
            .from(m)
            .where(m.username.eq("member1"))
            .fetchOne();

    assertThat(findMember.getUsername()).isEqualTo("member1");
}
select
        member0_.id as id1_1_,
        member0_.age as age2_1_,
        member0_.team_id as team_id4_1_,
        member0_.username as username3_1_ 
    from
        member member0_ 
    where
        member0_.username=?

 

 

startJQPL과 startQuerydsl 두개의 큰 차이가 있다. 

startJQPL은 문자형식으로 작성되어 아래와 같이 에러가 있을 때

사용자가 실행을 했을 때 메서드가 호출이 되면 에러가 있는것을 뒤늦게 발견한다. 즉 런타임 오류가 발생하는 것이다.

// JPQL 먼저 작성
@Test
public void startJPQL() {
     // member1을 찾아라.
    // JPQL에서는 parameter 바인딩을 해주고
    String qlString =
            "select m from Member m " +
            "where m.usernameㄸㄸ = :username";
    Member findMember = em.createQuery(qlString, Member.class)
            .setParameter("username", "member1")
            .getSingleResult();

    assertThat(findMember.getUsername()).isEqualTo("member1");
}

 

startQuerydsl은 에러가 컴파일 타임때 바로 알아차릴 수가 있다.

두 가지의 장점이 있는 것이다.

  • 파라미터 바인딩을 자동으로 해결해준다.
  • 컴파일 시점때 에러를 잡아준다.
@Test
public void startQuerydsl() {
    JPAQueryFactory queryFactory = new JPAQueryFactory(em);
    // 어떤 Q 멤버인지 이름을 주는 것
    QMember m = new QMember("m");


    // JPQL과 똑같다.
    Member findMember = queryFactory
            .select(m)
            .from(m)
            // 파라미터 바인딩을 안해도 eq를 해서 자동으로 JDBC의 prepare stament로 파라미터로 바인딩을 자동으로 한다.
            .where(m.usernameㄸㄷ.eq("member1"))
            .fetchOne();

    assertThat(findMember.getUsername()).isEqualTo("member1");
}

 

 

 

그리고 QuerydslBasicTest에서 아래 부분을 필드로 뺄 수가 있다.

JPAQueryFactory queryFactory = new JPAQueryFactory(em);
package study.querydsl.entity;


import com.querydsl.jpa.impl.JPAQueryFactory;
import org.aspectj.lang.annotation.Before;
import org.assertj.core.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.transaction.annotation.Transactional;

import javax.persistence.EntityManager;

import static org.assertj.core.api.Assertions.*;

@SpringBootTest
@Transactional
public class QuerydslBasicTest {

    @Autowired
    EntityManager em;

    JPAQueryFactory queryFactory;

    // 각 테스트 실행전에 데이터를 세팅을 하고 들어간다.
    @BeforeEach
    public void before() {
        // 필드레벨로 가져가도 괜찮다.
        // spring framework가 주입해주는 엔티티 자체가 멀티스레드에 문제없이 설계가 되어있다.
        // 여러 멀티스레드가 걸랴와도 현재 트랜잭션이 어디에 걸려있는지에 따라서 트랜잭션에 바인딩 되도록 다 분배를 해준다.
        // 즉 동시성 문제가 없다.
        queryFactory = new JPAQueryFactory(em);
        Team teamA = new Team("teamA");
        Team teamB = new Team("teamB");
        em.persist(teamA);
        em.persist(teamB);

        Member member1 = new Member("member1", 10, teamA);
        Member member2 = new Member("member2", 20, teamA);

        Member member3 = new Member("member3", 30, teamB);
        Member member4 = new Member("member4", 40, teamB);
        em.persist(member1);
        em.persist(member2);
        em.persist(member3);
        em.persist(member4);
    }

    // JPQL 먼저 작성
    @Test
    public void startJPQL() {
         // member1을 찾아라.
        // JPQL에서는 parameter 바인딩을 해주고
        String qlString =
                "select m from Member m " +
                "where m.username = :username";
        Member findMember = em.createQuery(qlString, Member.class)
                .setParameter("username", "member1")
                .getSingleResult();

        assertThat(findMember.getUsername()).isEqualTo("member1");
    }

    @Test
    public void startQuerydsl() {

        // 어떤 Q 멤버인지 이름을 주는 것
        QMember m = new QMember("m");


        // JPQL과 똑같다.
        Member findMember = queryFactory
                .select(m)
                .from(m)
                // 파라미터 바인딩을 안해도 eq를 해서 자동으로 JDBC의 prepare stament로 파라미터로 바인딩을 자동으로 한다.
                .where(m.username.eq("member1")) // 파라미터 바인딩 처리
                .fetchOne();

        assertThat(findMember.getUsername()).isEqualTo("member1");
    }
}

 

 

 

 

 

 

 

 

 

 

 

 

 

<출처 김영한: 실전! Querydsl >

https://www.inflearn.com/course/Querydsl-%EC%8B%A4%EC%A0%84/dashboard

 

실전! Querydsl - 인프런 | 강의

Querydsl의 기초부터 실무 활용까지, 한번에 해결해보세요!, - 강의 소개 | 인프런...

www.inflearn.com