서론
Spring Boot 프로젝트를 개발 및 운영하다보면 MyBatis라는 라이브러리를 사용해서 쿼리를 DB로 요청할 수 있으나
최근 들어서 JPA를 이용하는 서비스가 많아지고 있는 추세이다.
- 쿼리 운영 유지보수 측면에서 고려해봤을 때 복잡한 쿼리가 많은 경우 Native Query를 활용하지 않고 MyBatis 라이브러리를 사용하는 경우도 종종 있다.
JPA에서 제공하는 쿼리 메소드를 사용해도 기본적인 CRUD의 경우 어렵지 않다.
다만 복잡한 쿼리 혹은 요구사항에 따라 JPA에서 제공해주는 인터페이스로 활용이 어려울 경우 QueryDSL을 사용하게 된다.
- 인터페이스로만 구현할 경우 복잡성과 유지보수 측면에서 효율적이지 못함(가독성이 떨어짐)
이에 따라 Spring Boot 프로젝트에 QueryDSL을 함께 사용하는 경우가 많아지고 있음에 따라 이번 포스팅에서는
QueryDSL을 한번 끄적여보려구 한다.
QueryDSL 공식 홈페이지 및 지원 모듈
- QueryDSL 공식 홈페이지(http://querydsl.com/)에 가보면 JPA 뿐만 아니라 다양한 모듈에 지원하고 있다.
- 이는 다양한 데이터 베이스 환경에서 QueryDSL을 사용할 수 있도록 지원한다는 것을 확인할 수 있다.
Spring Data JPA vs QueryDSL
Spring Data JPA?
@Repository
public interface CompanyRepository extends JpaRepository<CompanyMaster, Long> {
List<CompanyMaster> findByCompanyLists(Long companySeq);
}
- JPA에서 사용하는 CRUD 인터페이스를 조금 더 쉽게 사용할 수 있도록 도와주는 모듈이다.
- JPA 기반의 Repository들을 쉽게 구현할 수 있도록 인터페이스를 제공해주며 JPARepository를 상속 받아 새로운 Repository
인터페이스를 구현이 가능하다. - 위의 예시 코드처럼 JPAREpository를 상속받은 CompanyRepository의 경우 CompanyMaster라는 Entity를 파라미터로 호출하여 CRUD 가능할 수 있도록 Spring Data JAP가 자동으로 코드를 생성하여 쉽게 쿼리할 수 있도록 지원해준다.
- 기본으로 제공해주는 인터페이스 뿐만 아니라 JPQL을 이용하여 객체 지향적인 쿼리 작성이 가능하다.
Spring Data JPA 장단점
- 장점
- JPARepository 인터페이스를 통한 간편한 CRUD 구현 가능하다.
- 메서드 명으로 쿼리 생성, 페이징, 정렬 기능 등 다양한 기능을 제공한다.
- 복잡한 쿼리(시퀀스 사용 등)에 대해 @Query 어노테이션을 통해 JPQL 또는 SQL 쿼리를 직접 작성이 가능하다.
- 단점
- 동적 쿼리 구현 및 복잡한 쿼리 작성이 어려움
- @Query 어노테이션을 활용해서 복잡한 조건 구현은 가능하지만 유지보수 측면에서 유연성이 떨어져 효율적이지 못하다.
- 메서드 명이 길어질 경우 가독성이 떨어질 수 있다.
- 메서드 명으로 쿼리를 생성함에 따라 조건이 많아질 경우 메서드 명이 길어질 수도 있다.
- 타입 세이프를 지원하지 않는다.
- 필드 타입이 잘못되었을 경우 컴파일 시 오류 확인이 어려움
- 동적 쿼리 구현 및 복잡한 쿼리 작성이 어려움
QueryDSL?
@Repository
@RequiredArgsConstructor
public class CompanyMasterCustomRepositoryImpl implements CompanyMasterRepository {
private final JPAQueryFactory jpaQueryFactory;
private final QCompanyMaster qcompanyMaster = QCompanyMaster.companyMaster;
@Override
public List<CompanyMaster> findCompanyByCustName(String custName) {
return jpaQueryFactory.select(qCompanyMaster)
.from(qCompanyMaster)
.where(qCompanyMaster.custName.eq(custName))
.fetch();
}
- QueryDSL은 Hibernate Query Language 쿼리 타입에 대해 안전하게 쿼리를 생성 및 관리해주는 프레임 워크이다.
- QueryDSL은 정적 타입을 이용하여 SQL과 같은 쿼리를 생성할 수 있다는 장점과 타입 세이프(type-safe)하게 쿼리 작성을
지원한다. - 위의 예시 코드와 같이 SQL의 쿼리 형태를 JAVA 코드로 작성할 수 있도록 지원해준다.
- 타입 세이프는 프로그램 실행되는 동안 잘못된 타입의 데이터를 사용할 경우 컴파일 혹은 런타임 오류가 발생하여 오류를 방지한다.
QueryDSL 장단점
- 장점
- 타입 세이프를 통해 컴파일 시 타입 오류에 따른 문제를 해결 할 수 있다.
- 복잡한 쿼리 및 동적 쿼리를 작성하기 쉽고 유지보수 측면에서 효율적이다.
- 여러 테이블 간 Join 구현
- 다양한 메서드 체이닝을 지원(where, and, or 등)
- 직접 쿼리를 작성하는 것이 아니며 JPA Entity 객체를 기준으로 쿼리를 작성하기 때문에
객체 지향적인 방식으로 처리가 가능하여 쿼리를 작성하는 것에 비해 로직을 구현하는 측면에서 효율적
- 단점
- QClass를 생성에 따른 러닝 커브
- QClass에 대한 이해가 필요
- QClass를 사용하기 위해서는 build 시점에 QClass를 생성할 수 있도록 설정 추가가 필요하다.
- 쿼리 자동생성이 불가능하다.
- QClass를 생성에 따른 러닝 커브
QClass?
- QueryDSL에서 사용되는 쿼리 타입 클래스(Query Type Class)를 의미한다.
- QClass를 통해 타입 세이프한 쿼리를 작성할 수 있도록 지원해주는 라이브러리
- QClass는 Entity 클래스 기반으로 자동으로 생성되며, 테이블과 매핑된 Entity의 필드들과의 관계를 가지고 있다.
- 이에 따라 QueryDSL을 사용하기 위해서는 QClass가 필요하다.
QClass 생성 방법
- QClass는 QureyDSL APT 기능을 통해서 자동으로 생성된다.
- 즉, gradle과 같은 build 도구에 QueryDSL 플러그인 설정을 추가하면 Build 시점에 QClass가 생성이 가능하다는 의미이다.
마무리
이번 포스팅에서는 간단하게 QueryDSL이 무엇인지, Spring Data JPA와의 차이를 알아봤다.
이번 포스팅을 하면서 사실 QueryDSL에 대해 중요하다는 건 알고 있지만 한편으로는 무조건적으로 사용해야하는걸까 싶었다.
그 이유는 개발자라는 직업이 개발을 잘해야 하고 신기술을 무조건적으로 따라가야 한다는 생각도 있지만
한편으로는 회사에서의 개발자의 역할은 개발한 서비스를 통해 수익을 내거나 수익과 연관성을 가져야 하는 측면에서는
간단한 서비스라면 굳이 QueryDSL을 사용하지 않아도 될 것 같다는 생각이였다.
이에 따라 무조건적으로 QueryDSL을 사용하는 것이 좋다고 볼 수는 없고 Spring Data JPA로만도 구현이 가능한 경우라면
QueryDSL을 사용하지 않아도 된다.
- 즉, 서비스의 특성이 복잡한 쿼리가 많고 유연성이 필요할 경우 QueryDSL을 사용해야 하지만
빠른 개발과 간단한 CRUD로 구성된 서비스면 오히려 QueryDSL을 사용하는 것이 오버스팩이 될 수 있다는의미이다.
이는, 저의 주관적인 의견이며 결국 기술을 도입하거나 사용하는 것은 개발자의 판단에 따라 달려있다.
다만 이번 포스팅을 통해 조금이나마 기초를 잡는데 도움이 되셨으면 한다.
다음 포스팅에서는 Spring Boot + QueryDSL 포스팅으로 찾아오겠습니다.
'Programing > Java & Spring' 카테고리의 다른 글
[Spring] 정의되지 않은 요청 파라미터에 대한 유효성 검증 및 Jackson 과 @EnableWebMvc의 관계성 (2) | 2024.11.12 |
---|---|
[Spring] QueryDsl 설정 및 Q파일 생성 안되는 이슈 해결(Gradle 8.x 이상 설정 방법) (0) | 2024.11.10 |
[MacOS] OpenJdk 17 -> temurin 17로 변경하기 (1) | 2024.10.06 |
[Spring] Utility Class에 대해서는 Static Method로 구성하는 것이 좋을까? (1) | 2024.09.11 |
[Spring] TimeZone에 대해 활용해보자 (0) | 2024.08.21 |