
- 실무에서는 조건에 따라서 실행되는 쿼리가 달라지는 동적 쿼리를 많이 사용함
- 주문 내역 검색을
Querydsl로 구현- 참고 링크 : http://querydsl.com/
package jpabook.jpashop.repository;
...
@Repository
@RequiredArgsConstructor
public class OrderRepository {
private final EntityManager em;
public void save(Order order){
em.persist(order);
}
public Order findOne(Long id){
return em.find(Order.class, id);
}
public List<Order> findAll(OrderSearch orderSearch){
String jpql = "select o from Order o join o.member m";
boolean isFirstCondition = true;
//주문 상태 검색
if(orderSearch.getOrderStatus() != null){
if(isFirstCondition){
jpql += " where";
isFirstCondition = false;
} else{
jpql += " and";
}
jpql += " o.status = :status";
}
//회원 이름 검색
if(StringUtils.hasText(orderSearch.getMemberName())){
if(isFirstCondition){
jpql += " where";
isFirstCondition = false;
} else{
jpql += " and";
}
jpql += " m.name like :name";
}
TypedQuery<Order> query = em.createQuery(jpql, Order.class)
.setMaxResults(1000);
if(orderSearch.getOrderStatus() != null){
query = query.setParameter("status", orderSearch.getOrderStatus());
}
if(StringUtils.hasText(orderSearch.getMemberName())){
query = query.setParameter("name", orderSearch.getMemberName());
}
return query.getResultList();
}
/*
JPA Criteria
*/
public List<Order> findAllByCriteria(OrderSearch orderSearch) {
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<Order> cq = cb.createQuery(Order.class);
Root<Order> o = cq.from(Order.class);
Join<Order, Member> m = o.join("member", JoinType.INNER); //회원과 조인
// 동적 쿼리에 대한 컨디션 조합을 Predicate을 활용해서 깔끔하게 만들 수 있음
List<Predicate> criteria = new ArrayList<>();
//주문 상태 검색
if (orderSearch.getOrderStatus() != null) {
Predicate status = cb.equal(o.get("status"),
orderSearch.getOrderStatus());
criteria.add(status);
}
//회원 이름 검색
if (StringUtils.hasText(orderSearch.getMemberName())) {
Predicate name =
cb.like(m.<String>get("name"), "%" +
orderSearch.getMemberName() + "%");
criteria.add(name);
}
cq.where(cb.and(criteria.toArray(new Predicate[criteria.size()])));
TypedQuery<Order> query = em.createQuery(cq).setMaxResults(1000); //최대 1000건
return query.getResultList();
}
}
build.gradle에 querydsl 관련 설정 코드 추가//querydsl 추가
buildscript {
dependencies {
classpath("gradle.plugin.com.ewerk.gradle.plugins:querydsl-plugin:1.0.10")
}
}
...
//querydsl 추가
apply plugin: 'io.spring.dependency-management'
apply plugin: "com.ewerk.gradle.plugins.querydsl"
...
dependencies {
...
//querydsl 추가
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"
}
...
//querydsl 추가
//def querydslDir = 'src/main/generated'
def querydslDir = "$buildDir/generated/querydsl"
querydsl {
library = "com.querydsl:querydsl-apt"
jpa = true
querydslSourcesDir = querydslDir
}
sourceSets {
main {
java {
srcDirs = ['src/main/java', querydslDir]
}
}
}
compileQuerydsl{
options.annotationProcessorPath = configurations.querydsl
}
configurations {
querydsl.extendsFrom compileClasspath
}

package jpabook.jpashop.repository;
import com.querydsl.core.types.dsl.BooleanExpression;
...
import static jpabook.jpashop.domain.QMember.member;
import static jpabook.jpashop.domain.QOrder.order;
@Repository
@RequiredArgsConstructor
public class OrderRepository {
...
/*
Querydsl
*/
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();
}
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);
}
}
Querydsl은 SQL(JPQL)과 모양이 유사하면서 자바 코드로 동적 쿼리를 편리하게 생성할 수 있음
실무에서는 복잡한 동적 쿼리를 많이 사용하게됨
Querydsl을 사용하면 높은 개발 생산성을 얻으면서 동시에 쿼리 오류를 컴파일 시점에 빠르게 잡을 수 있음동적 쿼리가 아니라 정적 쿼리인 경우에도 다음과 같은 이유로 Querydsl을 사용하는 것이 좋음
- 직관적인 문법
- 컴파일 시점에 빠른 문법 오류 발견
- 코드 자동완성
- 코드 재사용
JPQLnew명령어와는 비교가 안될 정도로 깔끔한 DTO 조회를 지원함
Querydsl은 JPQL을 코드로 만드는 빌더 역할을 할 뿐임JPQL을 잘 이해하면 금방 습득이 가능함Querydsl은 JPA로 애플리케이션을 개발할 때 선택이 아닌 필수