👻 QueryDSL이란 ?
SQL, JPQL 등을 코드로 작성할 수 있도록 해주는 프레임워크이며, 쿼리를 type-safe(컴파일시 에러 체크 가능)하게 Java 코드로 작성할 수 있다.
JPQL 이란?
JPA에서 지원하는 다양한 쿼리 방법 중 가장 단순한 조회 방법으로, SQL의 경우에는 DB 테이블을 대상으로 쿼리를 질의하지만, JPQL은 엔티티 객체를 대상으로 쿼리를 질의
JPQL의 경우 아래 코드에서 볼 수 있듯, 쿼리를 문자열로 입력하므로 오타가 발생하면 관리가 어렵고,
type-safe 불가능하여 런타임에서 해당 쿼리가 실행되어야만 오류를 발견할 수 있다는 단점이있다.
@Query("select t from Todo t inner JOIN fetch t.user where t.modifiedAt between :startDate and :endDate order by t.modifiedAt desc")
Page<Todo> findByModifyAt(LocalDateTime startDate, LocalDateTime endDate, Pageable pageable);
👉 QueryDSL 사용하는 이유
- JPQL과 달리 문자가 아닌 코드로 쿼리를 작성함으로써, 컴파일 시점에 문법 오류를 쉽게 확인할 수 있다.
- 동적인 쿼리 작성이 편리하다.
- 다양한 데이터베이스 시스템과 연동할 수 있으며, JPA, MyBatis 등 다양한 ORM 프레임워크와 연동 가능
😸 QueryDSL 설정
build.gradle
implementation 'com.querydsl:querydsl-jpa:5.0.0:jakarta'
annotationProcessor "com.querydsl:querydsl-apt:${dependencyManagement.importedProperties['querydsl.version']}:jakarta"
annotationProcessor "jakarta.annotation:jakarta.annotation-api"
annotationProcessor "jakarta.persistence:jakarta.persistence-api"
Q 클래스 생성
빌드를 마친 후 Gradle > Tasks > other > complie.java를 실행 시키면 Q클래스 파일이 생성된다.
QueryDsl Config 설정
@Configuration
public class JpaConfiguration {
@PersistenceContext
private EntityManager em;
@Bean
public JPAQueryFactory jpaQueryFactory() {
return new JPAQueryFactory(em);
}
}
😎 간단한 예제로 QueryDSL 사용해보기
현재 JPQL로 작성된 findByIdWithUser 메서드를 QueryDSL로 변경해보려고한다.
@Query("SELECT t FROM Todo t LEFT JOIN t.user WHERE t.id = :todoId")
Optional<Todo> findByIdWithUser(@Param("todoId") Long todoId);
먼저 커스텀 인터페이스를 작성한다.(QueryDSL Repository 에서 해당 인터페이스를 구현한다.)
public interface CustomTodoRepository {
Optional<Todo> findByIdWithUser(Long todoId);
}
구현체 클래스를 만든다.
@Repository
@RequiredArgsConstructor
public class CustomTodoRepositoryImpl implements CustomTodoRepository {
private final JPAQueryFactory jpaQueryFactory;
private final QTodo todo = QTodo.todo;
@Override
public Optional<Todo> findByIdWithUser(Long todoId) {
return Optional.ofNullable(jpaQueryFactory.selectFrom(todo)
.where(todo.id.eq(todoId))
.leftJoin(todo.user, user)
.fetchJoin()
.fetchFirst()
);
}
}
이후에는 기존의 TodoRepository에 CustomTodoRepository도 추가로 상속 받으면 된다.
public interface TodoRepository extends JpaRepository<Todo, Long> , CustomTodoRepository{
}
이렇게 하면 결과적으로 TodoRepository는 JpaRepository와 QueryDSLRepository의 메서드를 전부 가질 수 있게 된다.
커스텀 리포지토리에서는 QueryDSL을 사용할 메서드만 추상화해서 가지면된다.
이렇게 기존에 JPQL로 작성되어있던 메서드를 QueryDSL로 바꿔보며 간단하게나마 사용해봤는데 지금은 단순한 쿼리문이라 그렇게 막 편해졌다!! 이런 느낌은 없지만 쿼리가 좀 더 복잡해진다면 JPQL보다는 QueryDSL을 더 자주 사용할 것 같다는 생각이 들었다
무엇보다 자동완성을 사용할 수 있다는 점이 편했다
'TIL' 카테고리의 다른 글
Docker란 ? (0) | 2024.11.18 |
---|---|
JPA - QueryDSL을 이용한 동적쿼리 (0) | 2024.11.15 |
Service와 ServiceImpl 왜 나누는거지? (1) | 2024.11.13 |
JPA - 복합키와 식별 관계 매핑 (0) | 2024.11.12 |
미리 서명된 URL(Pre-signed url) 사용해보기 (0) | 2024.11.11 |