
Spring Data JPA에서
Item엔티티를 조회하기 위한ItemRepository인터페이스
JpaRepository<Item, Long>기본적인 CRUD, 페이징 등을 제공하는 인터페이스
QuerydslPredicateExecutor<Item> Querydsl을 통한 동적 쿼리 작성을 가능하게 한다.
동적 쿼리는 조건에 따라 쿼리의 WHERE, ORDER BY 등을 유동적으로 구성하는 것이다.
이름으로 검색할 수도 있고, 가격으로 검색할 수도 있고, 등록일 범위로도 검색할 수 있고 어떤 조건은 선택 안 할 수도 있다.
이럴 경우 고정된 쿼리 하나로 처리하기 어렵기 때문에, 입력된 조건만 가지고 쿼리를 구성하는게 동적 쿼리이다.
JPQL은 엔티티 기준으로 작성된다.
Native SQL 사용하여 동일 조건으로 조회
| 구분 | findByItemDetail (JPQL) | findByItemDetailByNative (Native SQL) |
|---|---|---|
| 언어 | JPQL (JPA Query Language) | 실제 SQL (DB 의존적) |
| 기준 | 엔티티 클래스 이름, 필드명 기준 | 실제 테이블명, 컬럼명 기준 |
| 이식성 | JPA가 추상화해서 DB 독립적 | 특정 DB에 의존적 |
| 예외 발생 | 필드명/엔티티 틀리면 컴파일 에러 | 런타임 오류 (SQL 문법 오류 등) |
| 성능 | JPA 내부 최적화 가능 | 성능 튜닝 직접 해야 함 |
| 사용 예 | JPA 중심 개발 | 복잡한 SQL, 성능이 중요한 쿼리, DB 특수 기능 필요할 때 |

Spring Data JPA는 메소드 이름으로 쿼리를 자동 생성하거나 @Query를 통해 쿼리를 지정할 수 있지만 복잡한 조건 검색, 동적 쿼리, 서브쿼리, join 등이 필요한 경우에는 Querydsl이나 직접 쿼리를 조립하는 방식이 필요하다
-> xxxRepositoryCustom + 구현 클래스 사용




코드는 ItemRepositoryCustom 인터페이스를 Querydsl 기반으로 구현한 클래스로
복잡한 조건 검색을 동적 쿼리로 처리하는 사용자 정의 리포지토리 구현체이다.
관리자 페이지용 상품 목록 조회
메인 페이지용 DTO 기반 상품 목록 조회
public ItemRepositoryCustomImpl(EntityManager em) {
this.queryFactory = new JPAQueryFactory(em);
}
Querydsl의 핵심 객체인 JPAQueryFactory를 생성자에서 초기화하는 부분이다.
ItemRepositoryCustomImpl
사용자 정의 레포지토리 구현체
EntityManager em
JPA의 핵심 객체로 DB 연결과 쿼리 실행을 담당
JPAQueryFactory
Querydsl 쿼리를 만들고 실행하기 위한 객체
this.queryFactory = new JPAQueryFactory(em);
EntityManager를 기반으로 쿼리 팩토리 생성
com.querydsl.core.types.dsl.BooleanExpression 클래스
Querydsl에서 조건절(WHERE 조건)을 표현하는 객체
Predicate처럼 동작하며, 조건을 동적으로 조립할 수 있다.
null을 반환하면 Querydsl이 해당 조건을 자동으로 무시한다.
| SQL | Querydsl |
|---|---|
where item_name like '%pen%' | QItem.item.itemName.like("%pen%") → BooleanExpression |
where price < 1000 | QItem.item.price.lt(1000) → BooleanExpression |
private BooleanExpression searchSellStatusEq(ItemSellStatus searchSellStatus) {
return searchSellStatus == null ? null :
QItem.item.itemSellStatus.eq(searchSellStatus);
}
판매 상태(ItemSellStatus)가 null이 아니면, 그 조건을 WHERE절에 넣고 null이면 조건 없이 전체 조회를 하는 메소드
private BooleanExpression regDtsAfter(String searchDateType)
최근 1일, 1주, 1개월, 6개월 등록 상품만 조회한다.
all 또는 null 이면 필터링 X
문자열 처리에 유용한 유틸리티 메소드들을 모아놓은 클래스
String str = " ";
StringUtils.isBlank(str); // true: null, 빈 문자열 "", 공백만 있어도 true
StringUtils.isEmpty(str); // false: null 또는 ""만 true
StringUtils.equals("abc", "ABC"); // false
StringUtils.equalsIgnoreCase("abc", "ABC"); // true
StringUtils.capitalize("hello"); // "Hello"
Querydsl의 메소드로 "해당 날짜 이후" 조건을 만드는 BooleanExpression
SQL로 표현하면 WHERE reg_time > '기준 시간'
관리자 페이지에서 상품 목록을 검색 조건에따라 페이징 + 동적 검색으로 조회
List<Item> content = queryFactory
.selectFrom(QItem.item)
.where(
regDtsAfter(itemSearchDto.getSearchDateType()), // 등록일 조건
searchSellStatusEq(itemSearchDto.getSearchSellStatus()), // 판매 상태 조건
searchByLike(itemSearchDto.getSearchBy(), // itemName or createdBy like 검색
itemSearchDto.getSearchQuery())
)
.orderBy(QItem.item.id.desc()) // id 역순 정렬
.offset(pageable.getOffset()) // 몇 번째부터 가져올지
.limit(pageable.getPageSize()) // 몇 개 가져올지
.fetch(); // 결과 조회
여러 개의 조건을 ,로 구분했지만, 내부적으로 AND로 연결된다.
메인 페이지에 상품 카드 형식으로 보여줄 상품 리스트 조회

Repository 구조를 정리하며, 이해가 부족했던 부분과 헷갈렸던 개념 위주로 정리했다.
기본적인 CRUD는 JpaRepository가 처리하지만, 복잡한 조건 검색을 위해 Querydsl과 사용자 정의 리포지토리 구현체도 함께 사용된다.
특히 BooleanExpression을 활용한 동적 쿼리 구성 방식이 유용하게 쓰인다.