티스토리 뷰
Spring 프로젝트를 진행하면서 Query DSL을 언제 도입할지에 대해 고민하던 중 좋은 타이밍이라 생각하여 도입했습니다.
내가 QueryDSL을 도입한 이유와 타이밍에 대해서 간략하게 정리하여 경험을 공유하고 합니다.
QueryDSL은 프로젝트 초기에 바로 도입하여 사용하는걸 권장하지만 현재 회사의 프로젝트를 시작하면서 최소한의 툴을 사용하면서 정말 필요할때 도입하고자 목표를 잡았었습니다.
본론으로 들어가기 전에 QueryDSL에 대해 간략하게 소개하고자 합니다.
QueryDSL이란?
QueryDSL은 Query 빌더로 조금 더 정확하게는 Jpa의 JPQL을 만들어주는 빌더입니다.
보통 Jpa Repository에서 자동으로 만들어주는 매핑 메소드를 생성하기 어렵거나 복잡한 상황에서 쿼리를 작성하고 데이터를 영속화하게 됩니다. 여기에서 사용하는 쿼리가 JPQL입니다. 물론 일반 SQL을 사용할 수 있지만 OOP의 특성을 가져가면서 객체 중심으로 DB연결 문제를 해결하는 JPA에서는 JPQL은 매우 중요한 요소 중 하나입니다. 왜냐하면 JPQL은 실제 생성한 엔티티객체를 이용하여 쿼리를 작성하기 때문입니다.
QueryDSL은 이런 문제를 해결하기 위해 JPQL을 코드를 이용해 작성하게 됩니다. 코딩 과정에서 문법에러를 미리 알 수 있으며 상황에 따라 유동적인 쿼리를 작성할 수 있는 엄청난 장점을 가지고 있습니다. 개발자 입장에서도 불확실한 String형태의 쿼리보다 수십 수백배는 안심할 수 있습니다. (물론 JPQL도 컴파일시 문법에러를 잡아주지만 Named 형태로 사용했을 때만 적용가능한 단점이 있습니다.)
QueryDSL 사용 전 후 비교
JPQL은 문법자체가 어렵진 않지만 데이터를 자유롭게 커스터마이징하기 힘들고 유연한 대처가 힘들게 됩니다. (enum과 같은 데이터를 사용할 경우 풀패키지 명을 작성해야하는 단점도 존재합니다.)
일반적으로 JPQL를 아래처럼 함수에 매핑하여 사용하게 되는데 쿼리가 길어지면 가독성이 기하급수적으로 떨어지게 됩니다. 유연한 조건을 이용할 수 없습니다. (동적쿼리 생성 불가..)
@Query("select c from Consultation c join fetch c.hospital join fetch "
+ "c.patient where c.idfConsultation = :id")
Optional<Consultation> findByIdWithHospital(@Param("id") long id);
enum을 사용할 경우 아래와 같은 괴랄한 Query를 작성해야합니다. 하나에서 두개정도의 문제라면 상관없겠지만 다양한 조건이 붙고 업데이트를 진행하다 보면 엄청난 스트레스로 다가오기 시작합니다.
select c from Consultation c join fetch c.category
where c.status = com.example.app.consultation.ConsultStatus.CANCEL
그래서 더 이상 늦기전에 QueryDSL을 이용하기로 결정했습니다. 드디어 본론입니다. 제가 QueryDSL을 도입한 타이밍의 이유는 다음 두가지 입니다.
1. 검색을 위한 유동적인 쿼리 생성
2. enum사용으로 인한 풀패키지 작성 등
search기능의 요구가 많아지고 다양한 조건에 따라 DB에서 데이터를 가져와야하고 다양한 불필요한 코드작성을 줄이고자 QueryDSL을 이용한 커스텀 레포를 만들었습니다.
위에 코드는 아래와 같이 탈바꿈됩니다.
BEFORE
@Query("select c from Consultation c join fetch c.hospital join fetch "
+ "c.patient where c.idfConsultation = :id")
Optional<Consultation> findByIdWithHospital(@Param("id") long id);
AFTER
@Override
public Optional<Consultation> findByIdWithHospital(long id) {
return Optional.ofNullable(
queryFactory
.selectFrom(consultation)
.join(consultation.hospital).fetchJoin()
.where(consultation.idfConsultation.eq(id))
.fetchOne()
);
}
String으로 만들어졌던 query가 코드형태로 변경되어 바로 디버그가 가능하며 가독성또한 좋아졌습니다. 뿐만아니라 BooleanBuilder를 통해 다양한 조건을 동시에 처리해주는 검색 함수도 만들 수 있습니다.
이렇게 된다면 여러 개로 쪼개져있는 JPQL을 공통의 목적으로 묶어 기능(역할) 중심의 구조로 설계를 개선할 수 있는 장점들도 존재합니다.
JPA를 사용한다면 필수적으로 QueryDSL을 고려해보면 좋을 것 같습니다!
그럼 오늘은 여기서 글 줄입니다.
'개발 > BACKEND' 카테고리의 다른 글
[Spring Boot] Rest API Doc 문서 작성 (feat.asciidoctor) (0) | 2022.08.14 |
---|---|
[간단] JaCoco를 이용해 test 커버리지 확인하기 (0) | 2022.06.23 |
[JPA] Custom Repository 구현 (0) | 2022.05.08 |
[JPA] 객체 연관관계 탐색 해제를 통한 성능개선 (0) | 2022.03.20 |
[Spring Boot] Security ProviderNotFoundException에러 해결 (0) | 2022.03.19 |
- Total
- Today
- Yesterday
- Lombok
- 신작
- 우주게임
- 용사
- Unity3D
- spring boot
- mobx
- JPA
- 스크럼
- spring
- frontend
- JPQL
- 개발
- studio108
- 사이드프로젝트
- QueryDSL
- 모험
- 이명규
- 보따리장사
- 게임개발
- 게임
- 유니티
- Java
- 튜토리얼
- 인디
- 턴드림
- 개발일지
- JIRA
- 게임 개발
- 인디게임
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |