QueryDSL

What is Querydsl

Querydsl은 JPA를 편하게 사용할 수 있게 도와주는 Java 프레임워크로 SQL, JPQL을 java코드로 작성 할 수 있도록 해주는 오픈소스이다. 대부분의 SQL언어를 문자열이 아닌 java type으로 작성이 가능하여 IDE와 컴파일 도움을 받기 쉽고 또한 JDBC도 추상화하여 native sql 언어로 직접 데이터베이스에 쿼리를 실행할 수 있다.

QueryDSL quick start

QueryDSL 설정은 여기서 확인하자. https://kha0213.github.io/jpa/querydsl-quick-start/

QueryDSL BASIC

1. Q-Type

모든 Q-Type 클래스는 기본 인스턴스를 제공한다.
기본인스턴스의 이름으로 실제 쿼리시 alias가 나간다.
혹시라도 alias가 겹치는 일이 있으면 안되기 때문에 일반적으로는 이렇게 사용한다.

QMember m = QMember.member;
final Member findMember = queryFactory
    .selectFrom(m)
    .fetchOne();

💻console

// jpql 이다.
select
    member1 
from
    Member member1 
where •••
    

new 연산자를 사용하여 Q-Type의 별칭을 주는 방법이다. 같은 테이블 조인할 때 사용한다.

QMember m = new QMember("m1");
    ••• Query  추가

💻console

// jpql 이다.
select
    m1 
from
    Member m1 
where •••
    

QueryDSL Grammer

  1. where
    • eq() : = 비교
    • ne() : != 비교
    • not() : 앞의 내용 부정문
    • isNotNull() : is not null

    • in() : in 문법
    • notIn() : not in 문법
    • between(a,b) : between a and b

    • goe() : 크거나 같다. (>=) // gt or equal
    • gt() : 크다
    • loe() : 작거나 같다 (<=)
    • lt() : 작다

    • like() : like문법 (%넣어줘야 한다.)
    • contains() : like문법인데 양쪽에 %넣은 효과.
    • startsWith() : like문법인데 뒤에 %넣은 효과.

기본적인 sql문법은 다 있다. 그 외에도 문법 보고 싶으면 ⇾

😀example


member.username.eq("young") // username = 'young'
member.username.ne("young") // username != 'young'
member.username.eq("young").not() // username != 'young'

member.username.isNotNull() // username 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,20) // age between 10 and 20

member.age.goe(20) // age >= 20  -- gt or equal
member.age.gt(20) // age > 20
member.age.loe(20) // age <= 20
member.age.lt(20) // age < 20

member.username.like("%mem") // like '%mem'
member.username.contains("mem") // like '%mem%'
member.username.startsWith("mem") // like 'mem%'

where() 안에 들어가는 조건은 , 로 구분하여 여러 개의 and 조건을 할 수 있고 .and()로 체인메서드로 할 수 있다.

member.username.eq("mem").and(member.age.gt(10))) // 하지만 괄호가 많이 생겨서 ,를 추천한다.
member.username.eq("mem"), member.age.gt(10)) // 이걸 추천한다.
member.username.eq("mem"), member.age.gt(10)), null // 중간의 null은 where절에 걸리지 않는다.
member.username.eq("mem").or(member.age.gt(10))) // 물론 or도 있다.
  1. result
    • fetch() : 리스트 조회, 데이터 없으면 빈 리스트 반환
    • fetchOne() : 단 건 조회 (결과 없으면 null, 둘 이상이면 에러)
    • fetchFirst() : 쿼리에 limit 1을 하고 fetchOne()
    • fetchResults() : 페이징 정보 포함, (total count 쿼리 추가 실행)
      • QueryResults 로 리턴된다. 다음은 QueryResults의 메서드이다.
        1. getTotal() : count 쿼리로 총 개수를 가져온다.
        2. getLimit() : limit를 구한다.
        3. getOffset() : offset을 구한다. (시작이 0)
        4. getResults() : fetch() 처럼 리스트 리턴한다.
    • fetchCount() : count 쿼리로 변경하여 count 수 조회

😀example

List<Member> fetch = queryFactory
    .selectFrom(member)
    .fetch();

Member fetchOne = queryFactory
    .selectFrom(member)
    .where(member.username.eq("member2"))
    .fetchOne(); // 단 건 조회 (2건 이상이면 에러!)

Member fetchFirst = queryFactory
    .selectFrom(member)
    .fetchFirst();

long fetchCount = queryFactory
    .selectFrom(member)
    .fetchCount();

QueryResults<Member> fetchResults = queryFactory
    .selectFrom(member)
    .fetchResults();
  1. sort
    • orderBy() 도 마찬가지로 여러 값을 ,를 사용하여 넣을 수 있다.
    • .nullsLast()로 null값이 맨 뒤에 오게 할 수도 있고, nullsFirst()로 null값이 맨 처음 오게 할 수도 있다.

😀example

List<Member> members = queryFactory
      .selectFrom(member)
      .orderBy(member.username.desc(), member.age.asc().nullsLast())
      .fetch();
  1. paging
    • offset(n) : n번째부터 시작 (0부터 시작한다.)
    • limit(k) : k개의 개수 출력

😀example

// 3번째부터 5개 가져오는 쿼리
final List<Member> members = queryFactory
        .selectFrom(member)
        .orderBy(member.username.desc().nullsLast())
        .offset(2) // 시작이 0부터
        .limit(5)
        .fetch();

실행된 SQL은 다음과 같다.
💻console

select 
    member0_.member_id as member_i1_0_, 
    member0_.age as age2_0_, 
    member0_.team_id as team_id4_0_, 
    member0_.username as username3_0_ 
from 
    member member0_ 
order by 
    case when member0_.username is null then 1 else 0 end, 
    member0_.username desc limit 2, 5

👍Tip 전체 개수를 구할 때에는 count쿼리를 따로 짤 필요 없이 fetchResults()로 가져오면 된다.

😀example

// count쿼리가 무조건 나가기 때문에 성능 고려
final QueryResults<Member> results = queryFactory
        .selectFrom(member)
        .orderBy(member.username.desc().nullsLast())
        .offset(7)
        .limit(5)
        .fetchResults();

assertThat(results.getTotal()).isEqualTo(10); // count 쿼리 전체 개수
assertThat(results.getLimit()).isEqualTo(5); // limit 개수
assertThat(results.getOffset()).isEqualTo(7); // 8번째부터
assertThat(results.getResults().size()).isEqualTo(3); // 8 9 10 3개
  1. group, having 나머지도 sql문법대로 group, having 사용가능하다. where처럼 체이닝 메서드로 활용해도 되고 ,를 사용하여 여러 파라미터로 넘겨주어도 된다.

😀example

// 1. 기본적인 집합 함수이다. 리턴은 엔티티가 아닌 Tuple로 가능하다. (Tuple은 get으로 값을 꺼낼 수 있다.)
final Tuple tuple = queryFactory
        .select(
                member.count(),
                member.age.sum(),
                member.age.avg(),
                member.age.max(),
                member.age.min()
        )
        .from(member)
        .fetchFirst();

// 2. group, having 사용가능하다.
final List<Tuple> tuples = queryFactory
    .select(team.name, member.age.avg())
    .from(member)
    .join(member.team, team)
    .groupBy(team.name)
    .having(member.age.avg().gt(10))
    .fetch();

Reference

공식 홈페이지: http://querydsl.com/
공식 레퍼런스:http://querydsl.com/static/querydsl/5.0.0/reference/html_single/
https://www.baeldung.com/querydsl-with-jpa-tutorial

태그: ,

카테고리:

업데이트:

댓글남기기