스프링/6. 스프링 DB-2

34. Querydsl 등장

sdafdq 2023. 10. 13. 07:17

D : 도메인

S : 특화

L : 언어

 

쿼리를 특정 도메인에 특화 시킨 제한적인 표현력을 가진 프로그래밍 언어

 

간결, 단순, 유창

 

쿼리에 특화된 간결한 언어이며, 다양한 DB의 쿼리를 통합해 지원해 주는 API.

 

 

처음 시작은,

쿼리도 사실 DB에 따라 다양함.

근데 이런 쿼리를 추상화해서 통합시켜 보자. 에서 출발. (실제로 여러 DB에서 Querydsl을 쓸 수 있음)

그럼 뭐 인터페이스에, 표준화 시키고 각 DB의 쿼리에 따라 구현해 놨겠지.

쿼리를 자바코드로 쓸 수 있게.

 

여러 DB의 query를 type-safe하게 쿼리로 만들어 줄 수 있음.(자바코드로 만들어 줄 수 있음. 오류 있으면 뱉으면서.)

 

 

잘은 모르겠는데, type safe한 쿼리를 작성하려면 코드가 좀 필요하다고 한다.

JPA같은 경우는 멤버 Entity나 DB의 테이블

SQL은 DB의 테이블

 

그럼 저걸 읽고 쿼리용 객체? Member Entity나 테이블이라면 QMember라는 객체를 만들어 줌.

@Annotation Processing Tool

애노테이션 처리 도구

뭐 그냥 @Entity 이거 도메인에 붙이면 된다는 소리임.

도메인 또는 테이블 코드 > APT > Q객체

이 순서로 만들어 짐.

APT는 저 @Annotation Processing Tool 저거임.

이런 게 만들어 진다고 함.

보면 숫자 생성, String 생성 등 있네. 조건생성 뭐 이런 건 없나?

 

 

 

여튼 Querydsl은 JPQL을 type-safe하게 작성하는 데 많이 사용됨.

 

그럼 다시, 다음 조건에서 Querydsl과 JPQL을 이용해 DB에서 데이터를 가져오려면?

나이 : 20~40살

성 : 김씨

 

순서 : 나이 많은 순

3명만.

@Entity
public class Member{
    @Id @GeneratedValue
    private Long id;
    private String name;
    private int age;
}

 

JPAQueryFactory query = new JPAQueryFactory (em)
QMember m = QMember.member;

뭐 대충 이렇게 EntityManager 주입 받아서 만들고,

QMember도 도메인에 @Entity 붙이고 Querydsl 쓰면 만들어 질 것이고

 

List<Member> list = query
    .select(m)
    .from(m)
    .where(
    	m.age.between(20,40).and(m.name.like("김%"))
    )
    .orderBy(m.age.desc())
    .limit(3)
    .fetch(m);

그러니까 List<Member> 해서 멤버들을 리스트로 가져오는 데,

select 문에다 m(멤버) 자체(그러니까, 멤버 전체)를 가져오고, 

from 은 m(m테이블로부터), 이고

where

멤버의 나이가 20,40 사이, 그리고 멤버의 이름이 김~~같은거

또 정렬하는데 m의 나이에 의해 내림차순.

한계는 3개까지

가져오기.

 

직역이 될 정도로 굉장히 직관적이다.

이렇게 하면,

 

select * from Member where age between 20 and 40 and name like '김%' order by age desc limit 3

 

m이 Member니까

 

여튼 이렇게 쿼리가 생성 됨.

굉장히 직관적임.

 

순서는 이러 함.

 

Querydsl > JQPL > SQL

 

Querydsl은 JPQL을 만들어 주는 빌더다.

 

 

장점

type-safe

단순함

 

단점

Q코드 생성을 위한 APT를 설정해야 하긴 하는데, 한번 해 놓으면 되니 편함.

 

 

동적쿼리 하기 쉬운게

BooleanBuilder 라는 게 있음.

 

String firstName = "김";
int min = 20,
int max = 40;

BooleanBuilder builder = new BooleanBuilder();
if(StringUtils.hasText(str)){
	builder.and(m.name.startsWith(firstName));
}

if(min != 0 && max != 0){
	builder.and(m.age.between(min, max));
}

List<Member> result = query
    .select(m)
    .from(m)
    .where(builder)
    .fetch(m)

저 BooleanBuilder에 

뭔가 조건이 맞으면

builder.and(내용)

해서 and + 내용을 추가시켜 뒀다고

(startsWith는 firstName으로 시작하는 그런건가 봄)

 

나중에 where할 때 인자로 넣어주면,

BooleanBuilder에 뭐가 있으면 where 하면서 넣어주고

없으면 where 자체를 추가 안하는 그런 식 일거 같음.

Querydsl이 JPQL을 만들어 주는 빌더 같은 거니.

 

 

조인도 지원 함.

QMember m = QMember.member;
QMemberCard mc = QMemberCard.memberCard;

List<Member> list = query
    .select(m)
    .from(m).join(m.memberCards, mc)
    .fetch(m);

m.memberCards가 MemberCard에 대한 id일테고,

mc가 아무래도 MemberCard, 엔티티나 테이블로 보면 됨. 추상화로써는 자바 객체로 보기 때문에 객체지만, 더 근본적인 부분은 테이블. m.memberCards 는 Member가 가지고 있는 MemberCard의 id, mc는 말 그대로 MemberCard

 

 

List<Member> result  =queryFactory
    .selectFrom(member)
    .orderBy(member.username.desc())
    .offset(1)
    .limit(2)
    .fetch();

아예 selectFrom 붙여서 쓸 수도 있구나. 전체 가져올 때 그런 듯.

offset은 1 하면 0부터 시작 제로인덱스 부터 라는데 잘 모름

limit는 최대 2회

 

SpringDataJPA의 약점은 조회인데,

이런 복잡한 조회를 Querydsl로 보완

 

물론 그래도 안되는 sql이 있는데,

그거는 myBatis나 jdbcTemplate 써서 그냥 직접 하면 됨.

 

'스프링 > 6. 스프링 DB-2' 카테고리의 다른 글

36. Querydsl 적용  (0) 2023.10.13
35. Querydsl 설정  (0) 2023.10.13
33. Querydsl  (0) 2023.10.13
32. 스프링데이터JPA 적용 2  (0) 2023.10.12
31. 스프링DataJpa 적용1  (0) 2023.10.12