Spring Data JPA에서 QueryDSL을 사용하기 위해서는 해당 기능을 지원하는 라이브러리를 추가해야 한다.
QueryDSL을 사용할 때는 QueryDSL이 제공하는 Predicate를 사용하여 동적 쿼리를 작성하고, Repository에 인터페이스를 작성하여 구현
QueryDSL 기본설정
의존성 추가 후 other-clean 후 compile.Java하여 build/generate에 QEntity 생성된거 확인하기
implementation 'com.querydsl:querydsl-jpa:5.0.0:jakarta'
annotationProcessor "com.querydsl:querydsl-apt:5.0.0:jakarta"
annotationProcessor "jakarta.annotation:jakarta.annotation-api"
annotationProcessor "jakarta.persistence:jakarta.persistence-api"
clean {
delete file('src/main/generated')
}
Repository에 QueryDSL 추가
Entity.java
@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@Entity
public class Entity {
@Id
private Long id;
private String name;
@Builder
...
}
EntityRepository.java
public interface EntityRepository extends JpaRepository<Entity, Long>, EntityQueryDslRepository {
}
EntityRepositoryCustom.java
public interface EntityQueryDslRepository {
List<Entity> findByName(String name);
}
EntityRepositoryCusomImpl.java
@Repository
public class EntityQueryDslRepositoryImpl implements EntityQueryDslRepository {
@PersistenceContext
private EntityManager entityManager;
@Override
public List<Entity> findByName(String name) {
QEntity qEntity = QEntity.Entity; // QueryDSL의 엔티티 클래스
return new JPAQuery<>(entityManager)
.select(qEntity)
.from(qEntity)
.where(qEntity.name.eq(name))
.fetch();
}
}
JPA와 QueryDSL은 각각 사용처를 분리해 두면 편하다고 한다.
- JPA를 사용하는 경우
- 기본적인 CRUD(Create, Read, Update, Delete) 기능을 구현할 때 JPA를 사용
- 단순한 데이터베이스 조작이 필요한 경우에는 JPA를 사용하여 쉽게 처리가 가능하다.
- QueryDSL을 사용하는 경우
- 복잡한 동적 쿼리를 작성해야 할 때 QueryDSL을 사용
- QueryDSL은 Fluent API를 제공하여 복잡한 쿼리를 Java 코드로 작성할 수 있어 코드 가독성을 높이고 오류를 줄일 수 있다.
- 복잡한 조인이나 서브쿼리, 다양한 필터링 조건을 가진 쿼리를 작성해야 할 때 QueryDSL을 사용하여 쉽게 처리할 수 있다.
- 복수의 엔티티 간의 연관 관계를 고려해야 하는 경우에도 QueryDSL을 사용하여 더 직관적이고 유연한 쿼리를 작성할 수 있다.
- 복잡한 동적 쿼리를 작성해야 할 때 QueryDSL을 사용
- QueryDSL + JPA를 동시에 사용하는 경우
- 위와 같이 2개의 EntityQueryDslRepository, EntityQueryDSLRepositoryImpl을 MemberRepository에 상속시켜서 MemberService 입장에서는 MemberRepository만 상속받게 하는 것이 유연한 프로그래밍 구조를 생성해 줄 수 있다.
JPAQueryFactory
import com.querydsl.jpa.impl.JPAQueryFactory;
public class MemberQueryDslRepositoryImpl implements MemberQueryDslRepository {
private final JPAQueryFactory queryFactory;
private final QMember member = QMember.member;
public MemberQueryDslRepositoryImpl(JPAQueryFactory queryFactory) {
this.queryFactory = queryFactory;
}
@Override
public Member findByEmail(String email) {
return queryFactory.selectFrom(member)
.where(member.email.eq(email))
.fetchOne();
}
}
JPAQueryFactory는 Querydsl을 사용하여 JPA 쿼리를 생성하기 위한 중요한 클래스다. EntityManager를 이용하여 JPA 쿼리를 생성하고 실행하는 데 사용되며, 주요 메서드는 다음과 같다.
- selectFrom():
- 쿼리의 시작점을 설정하고, 조회 대상 엔티티의 시작 테이블을 지정
- Querydsl의 QEntity 클래스를 인자로 받아 해당 엔티티를 기반으로 쿼리를 시작
- select():
- 쿼리 결과로 얻고자 하는 엔티티, 열 또는 표현식을 지정
- selectFrom() 이후에 사용되며, 특정 열 또는 표현식을 선택할 때 사용됩니다.
- where():
- 쿼리에 조건을 추가
- 엔티티의 필드 값을 비교하거나, 조건을 결합하는 등 다양한 조건을 지정할 수 있다.
- 주로 eq(), ne(), lt(), gt() 등의 메서드를 사용하여 비교
- groupBy():
- 그룹화를 위한 조건을 지정
- 일반적으로 집계 함수와 함께 사용되며, 결과를 그룹화하는 데 사용됨
- orderBy():
- 쿼리 결과의 정렬 순서를 지정
- 오름차순 또는 내림차순으로 정렬할 필드를 지정할 수 있다.
- fetch() 및 fetchOne():
- 쿼리 결과를 가져오는 메서드
- fetch()는 여러 결과를 가져오며, fetchOne()은 최대 하나의 결과만 가져온다.
- 보통 fetchOne() 메서드는 단일 결과를 반환하는 쿼리에서 사용된다.
- join():
- 쿼리에 조인을 추가
- 내부 조인, 외부 조인, 왼쪽 조인, 오른쪽 조인 등 다양한 유형의 조인을 지원
- limit() 및 offset():
- 결과를 제한하고 오프셋을 지정
- 페이지네이션을 구현할 때 사용된다.
QueryDslRepositorySupport
Spring Data JPA에서 제공하는 클래스로, Querydsl을 사용하여 JPA 쿼리를 작성하고 실행하는 데 도움을 준다.
QueryDslRepositorySupport를 상속하면 기본적으로 querydsl 필드가 제공되어 Querydsl의 JPAQueryFactory를 사용할 수 있다.
*쿼리를 쉽게 생성할 수 있도록 지원해 주는 부분도 있고, 페이징 처리에 유용한 기능들도 제공해준다.다음 코드를 참고하면 좋을 것 같다.
import com.querydsl.jpa.impl.JPAQuery;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.support.QuerydslRepositorySupport;
import org.springframework.stereotype.Repository;
@Repository
public class MemberQueryDslRepository extends QuerydslRepositorySupport {
public MemberQueryDslRepository() {
super(Member.class);
}
public Page<Member> findMembersByEmail(String email, Pageable pageable) {
// EntityManager를 사용하여 JPAQuery 생성
JPAQuery<Member> query = new JPAQuery<>(getEntityManager());
// Querydsl을 사용하여 동적 쿼리 작성
QMember member = QMember.member;
query.from(member)
.where(member.email.eq(email));
// applyPagination 메서드를 사용하여 Pageable 객체의 정보를 적용하여 페이징된 결과 반환
return getQuerydsl().applyPagination(pageable, query).fetch();
}
}
다음과 같은 추가 기능이 있다고 하니, 학습해보는것도 좋을 것 같다.
- Querydsl 컨텍스트 액세스: QueryDslRepositorySupport를 통해 Querydsl 컨텍스트에 접근할 수 있다. 이를 통해 Querydsl의 다양한 기능을 활용할 수 있다.
- 동적 쿼리 생성: QueryDslRepositorySupport를 사용하면 동적으로 쿼리를 생성할 수 있다. 예를 들어, 여러 조건에 따라 쿼리를 동적으로 생성할 수 있다.
- 페이징 및 정렬: QueryDslRepositorySupport를 사용하여 페이징 및 정렬된 쿼리를 작성할 수 있다. 이를 통해 특정 범위의 결과를 가져오고 정렬할 수 있다.
- 복잡한 조인 지원: QueryDslRepositorySupport를 사용하면 복잡한 조인을 수행하는 쿼리를 쉽게 작성할 수 있다. 예를 들어, 여러 테이블 간의 조인이 필요한 경우에 유용하다.
- 서브쿼리 작성: QueryDslRepositorySupport를 사용하여 서브쿼리를 작성할 수 있다. 이를 통해 복잡한 데이터 검색 및 필터링이 가능하다.
- 정적 타입 안전한 쿼리 작성: Querydsl을 사용하면 정적 타입 안전한 쿼리를 작성할 수 있다. 이는 오타나 오류를 미리 방지하여 안전한 쿼리 작성을 지원한다.
'Spring > JPA' 카테고리의 다른 글
JPA심화트랙(4) - JPA 유용한 기능들 소개 (1) | 2024.04.03 |
---|---|
JPA 심화트랙(3) - 연관관계 매핑 (2) | 2024.04.03 |
JPA 심화트랙(2) - Persistence Context(영속성 컨텍스트) (0) | 2024.04.02 |
JPA 심화트랙(1) - ORM의 필요성 (0) | 2024.04.01 |