먼저 JPQL 과 어떤 차이가 있는지 설명하도록 하겠습니다.

JPQL vs Querydsl

@SpringBootTest
@Transactional
public class QuerydslBasicTest {

    @PersistenceContext
    EntityManager em;

    @BeforeEach
    void setUp() {
        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);
    }

    @Test
    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
    void startQuerydsl() {
        JPAQueryFactory queryFactory = new JPAQueryFactory(em); //...1
        QMember m = QMember.member; //...2

        //member1을 찾아라.
        Member findMember = queryFactory
                .select(m)
                .from(m)
                .where(m.username.eq("member1"))
                .fetchOne();

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

}

  1. JPAQueryFactory 를 만들 때 EntityManager 를 같이 생성자에 넘겨야합니다.
  2. QMember 생성자에 넣어주는 String 은 어떤 QMember 인지 구분하는 이름입니다. (쉽게 말해서 DB의 별칭으로 생각하면 됩니다.)

JPQL 은 파라미터 바인딩을 문자열로 직접했지만 Querydsl 은 파라미터 바인딩을 자동 처리합니다.

JPQL 은 파라미터 바인딩 뿐만아니라 쿼리 자체를 문자열로 처리하기 때문에 만약 오타가 발생한다면 문제가 생긴 쿼리를 호출할 때 문제를 알 수 있습니다. 단순 문자열이라 실행이 되기 때문이죠.

하지만 Querydsl 은 컴파일 시점에 오류를 잡아줍니다. 쿼리를 자바 코드로 작성하기 대문이죠.

추가적으로 Querydsl 은 코드 어시스턴스가 어마어마해서 쉽게 작성할 수 있습니다.

QueryDSL 의 장점 요약

JPAQueryFactory를 필드로 리팩토링

@SpringBootTest
@Transactional
public class QuerydslBasicTest {

    @PersistenceContext
    EntityManager em;

		JPAQueryFactory queryFactory; //...1

    @BeforeEach
    void setUp() {
        queryFactory = new JPAQueryFactory(em); //...1
        
        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);
    }

    @Test
    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
    void startQuerydsl() {
        QMember m = QMember.member; //...2

        //member1을 찾아라.
        Member findMember = queryFactory
                .select(m)
                .from(m)
                .where(m.username.eq("member1"))
                .fetchOne();

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

}

JPAQueryFactory를 필드로 빼셔도 상관 없습니다.