-
데이터 접근 기술- QueryDSLBackEnd/Spring DB 2023. 2. 4. 09:11반응형
QueryDSL
- Query + Domain + Specific + Language
- 쿼리에 특화된 프로그래밍 언어
- 단순, 간결, 유창
- 다양한 저장소 쿼리 기능 통합
QueryDSL 장단점
장점
- 동적 쿼리 문제를 해결합니다.
- 쿼리 문장에 오타가 있어도 컴파일 시점에 오류를 막을 수 있습니다.
- 메서드 추출을 통해서 코드를 재사용할 수 있습니다.
- 자바 코드로 쿼리를 작성할 수 있습니다.
단점
- Q코드 생성을 위한 APT를 설정해야 합니다.
- 복잡한 쿼리의 경우 쿼리 분석이 어렵습니다. 전체 쿼리를 DBMS 툴로 조회하기 위해서는 실행되는 쿼리를 로깅하는 등의 방식으로 확인해야 합니다.
QueryDSL 이전 정리 글
QueryDSL 설정
의존성 추가(build.gradle)
dependencies { //Querydsl 추가 implementation 'com.querydsl:querydsl-jpa' annotationProcessor "com.querydsl:querydsl-apt:${dependencyManagement.importedProperties['querydsl.version']}:jpa" annotationProcessor "jakarta.annotation:jakarta.annotation-api" annotationProcessor "jakarta.persistence:jakarta.persistence-api" } //Querydsl 추가, 자동 생성된 Q클래스 gradle clean으로 제거 clean { delete file('src/main/generated') }
QueryDSL 적용
QueryDSL을 사용하려면 JPAQueryFactory가 필요하며, JPAQueryFactory는 JPQL을 만들기 때문에 EntityManager가 필요합니다. 설정 방식은 JdbcTemplate과 유사합니다. JPAQueryFactory를 스프링 빈으로 등록해서 사용해도 됩니다.
ItemRepository의 구현체와 Config 파일을 만들고 적용합니다.
package hello.itemservice.repository.jpa; import com.querydsl.core.BooleanBuilder; import com.querydsl.core.types.Predicate; import com.querydsl.core.types.dsl.BooleanExpression; import com.querydsl.jpa.impl.JPAQueryFactory; import hello.itemservice.domain.Item; import hello.itemservice.domain.QItem; import hello.itemservice.repository.ItemRepository; import hello.itemservice.repository.ItemSearchCond; import hello.itemservice.repository.ItemUpdateDto; import org.springframework.stereotype.Repository; import org.springframework.transaction.annotation.Transactional; import org.springframework.util.StringUtils; import javax.persistence.EntityManager; import java.util.List; import java.util.Optional; import static hello.itemservice.domain.QItem.*; @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); } @Override public Item save(Item item) { em.persist(item); return item; } @Override public void update(Long itemId, ItemUpdateDto updateParam) { Item findItem = em.find(Item.class, itemId); findItem.setItemName(updateParam.getItemName()); findItem.setPrice(updateParam.getPrice()); findItem.setQuantity(updateParam.getQuantity()); } @Override public Optional<Item> findById(Long id) { Item item = em.find(Item.class, id); return Optional.ofNullable(item); } @Override public List<Item> findAll(ItemSearchCond cond) { String itemName = cond.getItemName(); Integer maxPrice = cond.getMaxPrice(); return query .select(item) .from(item) .where(likeItemName(itemName), maxPrice(maxPrice)) .fetch(); } 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; } }
- save(), update(), findById(): 기본 기능들은 JPA가 제공하는 기본 기능을 사용합니다.
- findAll(): QueryDSL을 사용해서 동적 쿼리 문제를 해결합니다. BooleanBuilder를 사용해서 원하는 where 조건들을 넣어주면 됩니다. where(A, B)에 다양한 조건들을 넣을 수 있는데, 이렇게 넣으면 AND 조건으로 처리됩니다. where()에 null인 경우, 해당 조건은 무시됩니다.
package hello.itemservice.config; import hello.itemservice.repository.ItemRepository; import hello.itemservice.repository.jpa.JpaItemRepositoryV3; import hello.itemservice.service.ItemService; import hello.itemservice.service.ItemServiceV1; import lombok.RequiredArgsConstructor; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import javax.persistence.EntityManager; @Configuration @RequiredArgsConstructor public class QuerydslConfig { private final EntityManager em; @Bean public ItemService itemService() { return new ItemServiceV1(itemRepository()); } @Bean public ItemRepository itemRepository() { return new JpaItemRepositoryV3(em); } }
@Import(QuerydslConfig.class) @SpringBootApplication(scanBasePackages = "hello.itemservice.web") public class ItemServiceApplication {}
QueryDSL 예외
QueryDSL은 별도의 스프링 예외 추상화를 지원하지 않습니다. JPA처럼 @Repository에서 스프링 예외 추상화를 처리해줍니다.
[참고 정보]
반응형'BackEnd > Spring DB' 카테고리의 다른 글
트랜잭션(Transaction) 심화 (0) 2023.02.11 데이터 접근 기술- 활용 (0) 2023.02.09 데이터 접근 기술- Spring Data JPA (0) 2023.02.04 데이터 접근 기술- JPA (2) 2023.02.04 데이터 접근 기술- MyBatis (0) 2023.02.02