메서드명 쿼리 vs @Query vs QueryDSL 비교
Spring Data JPA는 쿼리를 작성하는 방법이 여러 가지입니다. 메서드명 유도, @Query(JPQL/Native), QueryDSL 중 언제 무엇을 선택할지 기준을 세우면, 저장소 코드가 짧고 안정적입니다.
1. 메서드명 쿼리(파생 쿼리)
interface OrderRepository extends JpaRepository<Order, Long> {
List<Order> findTop20ByStatusAndCreatedAtBetweenOrderByIdDesc(
Status status, LocalDateTime from, LocalDateTime to);
}
- 장점: 빠르고 타입 안전, 간단한 조건/정렬에 적합
- 한계: 조건이 늘면 메서드명이 폭발, 동적 조합이 어려움
2. @Query (JPQL/Native)
@Query("select o from Order o join fetch o.member m " +
"where (:status is null or o.status = :status) " +
"and o.createdAt between :from and :to")
List<Order> search(@Param("status") Status status,
@Param("from") LocalDateTime from,
@Param("to") LocalDateTime to);
- 장점: 복잡한 조인/페치, DTO 프로젝션,
countQuery분리 가능 - 한계: 문자열 쿼리라 리팩터링 시 깨지기 쉽고, 동적 조건 분기가 지저분해짐
3. QueryDSL (추천: 커스텀 리포지토리)
public interface OrderQueryRepository {
List<OrderView> search(OrderCond cond, Pageable pageable);
}
@Repository
@RequiredArgsConstructor
class OrderQueryRepositoryImpl implements OrderQueryRepository {
private final JPAQueryFactory query;
@Override
public List<OrderView> search(OrderCond cond, Pageable pageable) {
QOrder o = QOrder.order; QMember m = QMember.member;
BooleanBuilder where = new BooleanBuilder();
if (cond.status() != null) where.and(o.status.eq(cond.status()));
if (cond.from() != null) where.and(o.createdAt.goe(cond.from()));
if (cond.to() != null) where.and(o.createdAt.loe(cond.to()));
return query
.select(Projections.constructor(OrderView.class, o.id, m.name, o.createdAt))
.from(o).join(o.member, m)
.where(where)
.orderBy(o.id.desc())
.offset(pageable.getOffset())
.limit(pageable.getPageSize())
.fetch();
}
}
- 장점: 타입 안전, 동적 조건/정렬/프로젝션이 깔끔, 대규모 화면 적합
- 한계: 초기 설정(Q클래스 생성) 필요, 러닝커브
선택 기준
- 간단한 조회(필드 1~2개, 정렬 고정) → 메서드명
- 고정된 복잡 쿼리/DTO/페치조인 → @Query
- 동적 검색/필터/다양한 정렬/대시보드 → QueryDSL
프로젝션 전략
// 인터페이스 프로젝션
interface OrderSummary {
Long getId();
String getMemberName();
}
// 클래스 프로젝션 (생성자)
public record OrderView(Long id, String memberName, LocalDateTime createdAt) {}
테스트 팁
- 쿼리 결과 스키마(컬럼 개수/별칭)와 DTO 생성자/인터페이스 매핑을 반드시 검증
- 동적 조건은 파라미터 조합별 테이블 주도 테스트(경계값 from/to 포함)
FAQ
Q. 네이티브는 언제?
A. DB 함수/힌트/윈도우 함수가 꼭 필요할 때만. 가능하면 JPQL/QueryDSL 유지.
Q. 페치조인과 페이징?
A. XToOne은 비교적 안전하지만 컬렉션 페치조인은 권장하지 않습니다.
👉 2편: 메서드명 쿼리 vs @Query vs QueryDSL 비교
'Java & Spring' 카테고리의 다른 글
| 페이징 성능: 카운트 최적화·키셋 페이징 (0) | 2025.10.03 |
|---|---|
| @Transactional 전파/고립수준 이해 (1) | 2025.10.03 |
| 연관관계 주인/지연로딩 N+1 체크리스트 (0) | 2025.10.02 |
| Lombok 안전 사용 규칙(@Builder/@Value/@With) (0) | 2025.10.01 |
| JUnit5 + Mockito: Given-When-Then 패턴 (0) | 2025.10.01 |