김영한 개발자님의 스프링 DB 2편 강의를 수강하고 중요한 내용을 정리했습니다.
기존 query의 문제점
String sql = "select * from member" +
"where name like ?" +
"and age between ? and ?" // 공백이 없어 오류
// = select * from memberwhere name like ?and age between ? and ?"
만약 SQL이 클래스처럼 타입이 있고 자바 코드로 작성 할 수 있다면 type-safe이다.
Query(쿼리) + Domain(도메인) + Specific(특화) + Language(언어)
QueryDSL은 쿼리를 Java로 type-safe하게 개발할 수 있게 지원하는 프레임워크다. 주로 JPA쿼리(JPQL)에 사용하다.
Querydsl은 컴파일 시점에 쿼리용 Q타입을 생성한다.
@Repository
@Transactional
public class JpaItemRepositoryV3 implements ItemRepository {
private final EntityManager em;
private final JPAQueryFactory query;
public JpaItemRepositoryV3(EntityManager em) {
this.em = em;
this.query = new JPAQueryFactory(em);
}
public List<Item> findAllOld(ItemSearchCond itemSearch) {
String itemName = itemSearch.getItemName();
Integer maxPrice = itemSearch.getMaxPrice();
QItem item = QItem.item;
BooleanBuilder builder = new BooleanBuilder();
if (StringUtils.hasText(itemName)) {
builder.and(item.itemName.like("%" + itemName + "%"));
}
if (maxPrice != null) {
builder.and(item.price.loe(maxPrice));
}
List<Item> result = query
.select(item)
.from(item)
.where(builder)
.fetch();
return result;
}
@Override
public List<Item> findAll(ItemSearchCond cond) {
String itemName = cond.getItemName();
Integer maxPrice = cond.getMaxPrice();
List<Item> result = query
.select(item)
.from(item)
.where(likeItemName(itemName), maxPrice(maxPrice))
.fetch();
return result;
}
private BooleanExpression likeItemName(String itemName) {
if (StringUtils.hasText(itemName)) {
return item.itemName.like("%" + itemName + "%");
}
return null;
}
private BooleanExpression maxPrice(Integer maxPrice) {
if (maxPrice != null) {
return item.price.loe(maxPrice);
}
return null;
}
}
Querydsl을 사용하려면 JPAQueryFactory
가 필요하다. JPAQueryFactory
는 JPA 쿼리인 JPQL을 만들기 때문에 EntityManager
가 필요하다.
BooleanBuilder
를 사용해서 원하는 where
조건들을 넣어주면 된다.findAllOld
에서 작성한 코드를 깔끔하게 리팩토링 했다.where(A,B)
에 다양한 조건들을 직접 넣을 수 있는데, 이렇게 넣으면 AND 조건으로 처리된다. 참고로 where()
에 null
을 입력하면 해당 조건은 무시한다.likeItemName()
, maxPrice()
를 다른 쿼리를 작성할 때 재사용 할 수 있다는 점이다. 쿼리 조건을 부분적으로 모듈화 할 수 있다.