다음으로 - 스프링 데이터 JPA와 QueryDSL
- 김영한님의 실전! 스프링 부트와 JPA 활용2 - API 개발과 성능 최적화 강의를 기반으로 순수 JPA 리포지토리의 반복 코드를 자동화하는 스프링 데이터 JPA와, 동적 쿼리를 자바 코드로 안전하게 작성할 수 있는 QueryDSL의 개념과 적용 방법을 정리함
전체 개요
- 순수 JPA 리포지토리의 반복 코드를 자동화하는 스프링 데이터 JPA와, 동적 쿼리의 한계를 해결하는 QueryDSL을 함께 사용하여 생산성을 향상시킴
스프링 데이터 JPA
기존 순수 JPA 리포지토리
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
@Repository
@RequiredArgsConstructor
public class MemberRepository {
private final EntityManager em;
public void save(Member member) {
em.persist(member);
}
public Member findOne(Long id) {
return em.find(Member.class, id);
}
public List<Member> findAll() {
return em.createQuery("select m from Member m", Member.class)
.getResultList();
}
public List<Member> findByName(String name) {
return em.createQuery("select m from Member m where m.name = :name", Member.class)
.setParameter("name", name)
.getResultList();
}
}
스프링 데이터 JPA 적용 후
1
2
3
4
5
public interface MemberRepository extends JpaRepository<Member, Long> {
// 메서드 이름만으로 JPQL 자동 생성
// select m from Member m where m.name = :name
List<Member> findByName(String name);
}
-
findOne()은 스프링 데이터 JPA에서findById()로 변경해야 함
변경 전후 비교

- 주요 특징
JpaRepository인터페이스를 상속하면 기본 CRUD가 모두 제공됨findByName처럼 메서드 이름으로 JPQL 쿼리를 자동 생성함- 개발자는 인터페이스만 작성하면 되고, 구현체는 애플리케이션 실행 시점에 스프링 데이터 JPA가 주입함
- 스프링 데이터 JPA는 JPA를 기반으로 동작하므로 JPA 자체를 잘 이해하는 것이 가장 중요함
QueryDSL
동적 쿼리 문제

- 실무에서는 조건에 따라 실행되는 쿼리가 달라지는 동적 쿼리를 많이 사용함
- 순수 JPQL로는 동적 쿼리를 작성하기 어렵고 오류가 런타임에서야 발견됨
QueryDSL 적용 코드
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
public List<Order> findAll(OrderSearch orderSearch) {
QOrder order = QOrder.order;
QMember member = QMember.member;
return query
.select(order)
.from(order)
.join(order.member, member)
.where(
statusEq(orderSearch.getOrderStatus()),
nameLike(orderSearch.getMemberName())
)
.limit(1000)
.fetch();
}
// null 반환 시 where 조건에서 자동 제외
private BooleanExpression statusEq(OrderStatus statusCond) {
if (statusCond == null) {
return null;
}
return order.status.eq(statusCond);
}
private BooleanExpression nameLike(String nameCond) {
if (!StringUtils.hasText(nameCond)) {
return null;
}
return member.name.like(nameCond);
}
build.gradle 설정
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
plugins {
}
dependencies {
// Querydsl 추가
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클래스 생성 위치를 지정하는 설정
clean {
delete file('src/main/generated')
}
QueryDSL 장점
| 항목 | JPQL (문자열) | QueryDSL (자바 코드) |
|---|---|---|
| 문법 오류 발견 | 런타임 | 컴파일 시점 |
| 동적 쿼리 | 문자열 조합으로 복잡 | BooleanExpression으로 간결 |
| 코드 자동완성 | 불가 | IDE 지원 |
| 코드 재사용 | 어려움 | 메서드로 재사용 가능 |
| DTO 조회 | new 명령어로 복잡 |
Projections으로 깔끔 |
- QueryDSL은 JPQL을 코드로 만드는 빌더 역할을 함
요약 정리
- 스프링 데이터 JPA는
JpaRepository인터페이스를 상속하면 기본 CRUD가 자동 제공되고, 메서드 이름만으로 JPQL 쿼리를 자동 생성하여 반복 코드를 제거함 - QueryDSL은 동적 쿼리를 자바 코드로 작성하여 컴파일 시점에 오류를 발견할 수 있고,
BooleanExpression을 활용해 조건을 조합하며 코드 재사용이 가능함 - QueryDSL에서
null을 반환하면 해당where조건이 자동으로 제외되어 동적 쿼리를 간결하게 구현할 수 있음 - 두 기술 모두 JPA 위에서 동작하므로 JPA에 대한 깊은 이해가 전제되어야 함