ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 03. Querydsl 기본 문법
    BackEnd/Querydsl 2021. 7. 17. 15:36
    반응형

    1. Querydsl 기본 문법


    package com.spring.querydsl;

    import com.querydsl.jpa.impl.JPAQueryFactory;
    import org.junit.jupiter.api.BeforeEach;
    import org.junit.jupiter.api.Test;
    import org.springframework.boot.test.context.SpringBootTest;
    import org.springframework.transaction.annotation.Transactional;
    import com.spring.querydsl.entity.Member;
    import com.spring.querydsl.entity.QMember;
    import com.spring.querydsl.entity.Team;
    import javax.persistence.EntityManager;
    import javax.persistence.PersistenceContext;
    import static org.assertj.core.api.Assertions.*;
    import static com.spring.querydsl.entity.QMember.*;


    @SpringBootTest
    @Transactional
    public class QuerydslBasicTest {
        @PersistenceContext
        EntityManager em;

        JPAQueryFactory queryFactory;

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

        @Test
        public void startQuerydsl() {
            // EntityManager JPAQueryFactory 생성
            // JPAQueryFactory queryFactory = new JPAQueryFactory(em); > 필드 선언으로 변경


             // 기본 인스턴스 static import
            // QMember m = new QMember("m");
            // select m from Member m where m.username = :username;
            Member findMember = queryFactory
                         .select(member)
                         .from(member)
                         .where(member.username.eq("member1")) // Parameter Binding
                         .fetchOne();

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


      > Querydsl은 JPQL 빌더

      > JPQL: 문자(실행 시점 오류), Querydsl: 코드(컴파일 시점 오류)

      > JPQL: 파라미터 바인딩 직접, Querydsl: 파라미터 바인딩 자동 처리

      > JPAQueryFactory를 필드로 제공하면 동시성 문제는 JPAQueryFactory를 생성할 때 제공하는 EntityManager(em)에 달려있다. 스프링 프레임워크는 여러 쓰레드에서 동시에 같은 EntityManager에 접근해도, 트랜잭션 마다 별도의 영속성 컨텍스트를 제공하기 때문에 동시성 문제가 없다.

     

    Q클래스 인스턴스 사용 방법

    1) QMember qMember = new QMember("m"); //별칭 직접 지정

    2) QMember qMember = QMember.member; //기본 인스턴스 사용

     

    기본 인스턴스를 static import와 함께 사용

      > 같은 테이블을 조인해야 하는 경우가 아니면 기본 인스턴스 사용하기.

     

    참고) 다음 설정을 추가하면 실행되는 JPQL을 볼 수 있다.

      > spring.jpa.properties.hibernate.use_sql_comments: true

     

    2. Querydsl 조회


    package com.spring.querydsl;

    import com.querydsl.core.Tuple;
    import com.querydsl.jpa.impl.JPAQueryFactory;
    import org.junit.jupiter.api.BeforeEach;
    import org.junit.jupiter.api.Test;
    import org.springframework.boot.test.context.SpringBootTest;
    import org.springframework.transaction.annotation.Transactional;
    import com.spring.querydsl.entity.Member;
    import com.spring.querydsl.entity.QMember;
    import com.spring.querydsl.entity.Team;
    import javax.persistence.EntityManager;
    import javax.persistence.PersistenceContext;
    import java.util.List;

    import static org.assertj.core.api.Assertions.*;
    import static com.spring.querydsl.entity.QMember.*;


    @SpringBootTest
    @Transactional
    public class QuerydslBasicTest {
        @PersistenceContext
        EntityManager em;

        JPAQueryFactory queryFactory;

        @BeforeEach
        public void before() {
            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("member1", 20, teamA);
            Member member3 = new Member("member1", 20, teamB);
            Member member4 = new Member("member1", 40, teamB);
            em.persist(member1);
            em.persist(member2);
            em.persist(member3);
            em.persist(member4);
        }

        @Test
        public void search() {
            // com.querydsl.core.Tuple : 프로젝션(select 대상 지정) 대상이 둘 이상일 때 사용
            List<Tuple> result = queryFactory
            // select, from selectFrom으로 합칠 수 있다.
            // .selectFrom(member)
            .select(member.username,
            // 집합 함수
                     member.count(),
                     member.age.sum(),
                     member.age.avg(),
                     member.age.max(),
                     member.age.min())
            .from(member)
            // 검색 조건은 .and(), .or()를 메서드 체인으로 연결할 수 있다.
            // .where(member.username.eq("member1").and(member.age.gt(10)))
            // -> AND 조건을 파라미터로 처리하면 null 값은 무시한다.
            .where(member.username.eq("member1"), member.age.gt(10))
            /*
            member.username.eq("member1") // username = 'member1'
            member.username.ne("member1") //username != 'member1'
            member.username.eq("member1").not() // username != 'member1'
            member.username.isNotNull() //이름이 is not null
            member.age.in(10, 20) // age in (10,20)
            member.age.notIn(10, 20) // age not in (10, 20)
            member.age.between(10,30) //between 10, 30
            member.age.goe(30) // age >= 30
            member.age.gt(30) // age > 30
            member.age.loe(30) // age <= 30
            member.age.lt(30) // age < 30
            member.username.like("member%") //like 검색
            member.username.contains("member") // like ‘%member%’ 검색
            member.username.startsWith("member") //like ‘member%’ 검색
            */
            // Group by
            .groupBy(member.username, member.age)
            .having(member.age.gt(10))

            // Sort
        
        // 1.
    회원 나이 내림차순(desc), 2. 회원 이름 올림차순(asc)
            // * 2에서 회원 이름이 없으면 마지막에 출력(nulls last)
            // nullsLast() , nullsFirst() : null 데이터 순서 부여
            .orderBy(member.age.desc(), member.username.asc().nullsLast())
            // Paging
            // .offset(1) //0부터 시작(zero index)
            // .limit(2) //최대 2건 조회
            .fetch();

            for (Tuple tuple : result) {
               System.out.println("t=" + tuple);
            }
        }
    }


    3. Querydsl 결과 조회

      1) fetch() : 리스트 조회, 데이터 없으면 빈 리스트 반환

      2) fetchOne() : 단 건 조회

        > 결과가 없으면 : null

        > 결과가 둘 이상이면 : com.querydsl.core.NonUniqueResultException

      3) fetchFirst() : limit(1).fetchOne()

      4) fetchResults() : 페이징 정보 포함, total count 쿼리 추가 실행

        > count 쿼리에 조인이 필요없는 성능 최적화가 필요하다면, count 전용 쿼리를 별도 분리

      5) fetchCount() : count 쿼리로 변경해서 count 수 조회

     

     

    반응형

    'BackEnd > Querydsl' 카테고리의 다른 글

    06. Querydsl Case  (0) 2021.07.27
    05. Querydsl Subquery  (0) 2021.07.25
    04. Querydsl Join  (0) 2021.07.18
    01. Querydsl 레퍼런스 문서  (0) 2021.07.11
    02. Querydsl 설정  (0) 2021.07.11

    댓글

Designed by Tistory.