서론
토이 프로젝트 진행 중 아래와 같은 쿼리 사용이 필요했고, QueryDSL을 한 번 사용해보기로 했음.
select C.CHAMPION_ID, C.PRICE, ROUND((C.PRICE-CP.PRICE)/CP.PRICE*100) as PERCENT
from Champion C, (select CC.CHAMPION_ID, CC.PRICE
from ChampionPriceLog CC
where (CC.CHAMPION_ID, CC.CREATE_DATE) in(select CCC.CHAMPION_ID, MAX(CCC.CREATE_DATE) AS CREATE_DATE
from ChampionPriceLog CCC
group by CCC.CHAMPION_ID)
order by CC.CHAMPION_ID) as CP
where C.CHAMPION_ID = CP.CHAMPION_ID;
QueryDSL
간략하게 QueryDSL에 대한 조사를 했다.
QueryDSL이란 하이버네이트 쿼리 언어의 쿼리를 생성 및 관리해주는 오픈소스 프레임워크이며
위의 공식 문서에서 알 수 있듯이 JPA뿐 아니라 여러 언어를 지원한다.
QueryDSL은 정적 타입을 이용하여 SQL과 같은 쿼리를 생성할 수 있게 해준다.
QueryDSL JPA
진행중인 토이 프로젝트가 스프링부트를 사용하기 때문에, QueryDSL JPA에 대해 알아볼 필요가 있다.
QueryDSL JPA는 SQL, JPQL을 코드로 작성할 수 있도록 해주는 빌더 API이며, Entity클래스와 매핑되는 QClass라는 객체를 사용해 쿼리를 실행한다.
JPQL 이란?
공부를 위해 포스팅해놓은 링크가 있으니 참조하자.
QClass 란?
위에서 언급했든 QueryDSL은 컴파일 단계에서 Entity를 매핑하여 QClass를 생성한다.
JPAAnnotationProcessor 클래스(docs 링크)가 컴파일 시점에 작동하여 @Entity 애너테이션을 찾아 분석하여 Entity와 형태가 같은 Static Class로 QClass를 생성하며, QueryDSL은 쿼리 작성 시 이 QClass를 기반으로 쿼리를 실행하게 된다.
QueryDSL JPA 사용 이유
그렇다면 QueryDSL을 왜 사용할까?
JPQL은 결국 쿼리를 문자열로 입력하기 때문에, 오타가 발생하거나 관리하기가 어렵고, 컴파일 단계에서가 아닌 런타임 시 오류를 확인할 수 있다는 문제가 있다.
QueryDSL은 단순 문자열이 아닌 코드를 통해 작성하기 때문에, 코드 작성자의 실수(오타)를 예방할 수 있으며, 객체 지향적인 개발이 가능하다. 또한 컴파일 단계에서도 오류를 빠르게 발견할 수 있다는 장점이 있다.
아래의 예시는 JPQL과 QueryDSL의 같은 상황에 대한 사용 예시이다.
String jpql = "select * from Member m join Point p on p.member_id = m.id"
List<Member> result = em.createQuery(jpql, Member.class).getResultList();
return jpaQueryFactory
.from(member)
.join(member.point, point)
.fetch();
JPQL이 객체지향 쿼리라고는 하지만, 결국 String 쿼리를 객체로 변환시켜주는 과정이 필요하기 때문에, 문자열 입력 시 오타와 같은 상황이 충분히 발생 가능하며, 문자열이 잘못됐더라도 컴파일 단계에서는 확인이 불가능한 것을 알 수 있다.
QueryDSL은 쿼리를 문자열이 아닌, 코드화하여 전달하기 때문에 위에서 언급했던 장점들을 가져갈 수 있다.
참조
2023.04 ~ 백엔드 개발자의 기록
포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!