Querydsl
- 쿼리의 문제점
- 쿼리는 문자이기에 타입 체크가 불가능하다.
- 실행하기 전까지 작동 여부를 확인할 수 없다.
- JPQL은 type-safe하다.
- 컴파일 시 에러 체크 가능
- JPA에서 QUERY 방법
- JPQL(HQL) : SQL 쿼리와 비슷해서 익숙하지만 type-safe가 아니며 동적 쿼리 생성이 어렵다.
- Criteria API : 동적 쿼리 생성이 쉽지만 type-safe가 아니고 너무 복잡하고 알아야할 것이 많다.
- MetaModel Criteria API(type-safe) : type-safe하지만 너무 복잡하다.
- QueryDSL : 쿼리를 Java로 type-safe하게 개발할 수 있도록 지원하는 프레임워크
- 쿼리에 특화된 프로그래밍 언어로 다양한 저장소 쿼리 기능을 통합
- type-safe하고 단순하지만 Q코드 생성을 위한 APT를 설정해야한다.
- DSL(Domain Specific Language) : 도메인 특화 언어
- 주로 JPA 쿼리(JPQL)에 사용
- APT(Annotation Processing Tool) : 어노테이션을 처리하고 정보를 바탕으로 코드를 생성하거나 추가 작업을 수행하는 기능을 제공한다.
- 주로 컴파일 타임에 동작하고 작성한 어노테이션을 분석해서 자동으로 부가적인 코드(메타 데이터, boilerplate 코드) 를 생성하거나 검증 작업을 수행
- 스프링 데이터 JPA의 약점인 조회는 Querydsl로 보완
- 단순한 경우 Spring Data JPA 사용
- 복잡한 경우 Querydsl 직접 사용
Querydsl 설정
//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 설정 build.gradle - 스프링 부트 2.xx 버전
- 스프링 부트 3.xx 버전의 경우 jpa 대신 jakarta로 변경
- 검증 - Q 타입 생성 확인 방법
- settings -> Preferences -> Build, Execution, Deployment -> Build Tools -> Gradle
- Gradle인 경우
- 우측 바에서 Gradle -> Tasks -> build -> clean
- Gradle -> Tasks -> other -> compileJava
- 디렉토리 build -> generated -> sources -> annotationProcessor -> java/main 하위에 Q클래스가 생성되었는지 확인
- 콘솔 사용 시 ./gradlew clean compileJava
- Intellij IDEA의 경우
- 상단에서 Build -> Build Project / Rebuild를 하거나 main 애플리케이션이나 test 클래스 실행
- src/main/generated 하위에 Q클래스가 생성되었는지 확인
- Gradle인 경우
- settings -> Preferences -> Build, Execution, Deployment -> Build Tools -> Gradle
- Q타입은 컴파일 시점에 자동 생성되므로 버전관리(GIT)에 포함하지 않는 것이 좋다. (.gitignore에서 설정)
- Gradle 옵션을 선택하면 Q타입은 gradle build 폴더 아래에 생성되므로 해당 디렉토리 하위를 버전관리에 포함하지 않아야하지만 대부분 gradle build 폴더를 git에 포함하지 않기 때문에 자연스럽게 해결된다.
- IntelliJ 옵션을 선택하면 src/main/generated 하위에 Q타입이 생성되기 때문에 버전관리에 포함하지 않도록 설정해야 한다.
- Q타입 삭제
- IntelliJ 옵션의 경우 직접 삭제해야 한다.
- Gradle 옵션의 경우 gradle clean을 실행하면 된다.
Querydsl 적용
@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) {...}
@Override
public void update(Long itemId, ItemUpdateDto updateParam) {...}
@Override
public Optional<Item> findById(Long id) {...}
@Override
public List<Item> findAll(ItemSearchCond cond) {
String itemName = cond.getItemName();
Integer maxPrice = cond.getMaxPrice();
//별칭 as 적용
// QItem item = new QItem("i"); //이렇게 사용해도 됨
// QItem.item; //Q타입 내부에 인스턴스를 가지고 있기에 static import해서 사용해도 됨
//동적 쿼리
BooleanBuilder builder = new BooleanBuilder();
if (StringUtils.hasText(itemName)) {
builder.and(item.itemName.like("%" + itemName + "%"));
}
if (maxPrice != null) {
builder.and(item.price.loe(maxPrice));
}
return query
.select(item)
.from(item)
.where()
.fetch();
}
}
- Querydsl 예제 코드
- Querydsl을 사용하기 위해서 JPAQueryFactory가 필요하다.
- JPAQueryFactory는 JPQL을 만들기 때문에 EntityManager가 필요하다.
- findAll()
- Q타입 클래스를 사용법
- 생성자로 인스턴스를 생성하고 별칭(as)을 지정해서 사용할 수 있다.
- Q타입 클래스 내부에 인스턴스가 있기에 static import해서 사용할 수 있다.
- 동적 쿼리
- BooleanBuilder를 사용해서 원하는 where 조건들을 넣어줄 수 있다.
- Q타입 클래스를 사용법
- 쿼리 문장에 오타가 있어도 컴파일 시점에 오류를 막을 수 있다.
- Querydsl을 사용하기 위해서 JPAQueryFactory가 필요하다.
@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 Predicate maxPrice(Integer maxPrice) {
if (maxPrice != null) {
return item.price.loe(maxPrice);
}
return null;
}
- findAll() 리팩토링 예제 코드
- where()에 다양한 조건을 직접 넣을 수 있고 ,로 구분하면 AND 조건으로 처리된다.
- null을 입력하면 해당 조건은 무시된다.
- likeItemName(), maxPrice()로 메소드 추출함으로 다른 쿼리를 작성할 때도 재사용할 수 있다.
- 쿼리 조건을 부분적으로 모듈화할 수 있다.
- where()에 다양한 조건을 직접 넣을 수 있고 ,로 구분하면 AND 조건으로 처리된다.
- Querydsl은 별도의 스프링 예외 추상화를 지원하지 않기에 @Repository를 사용하면 된다.
정리
- Querydsl : 쿼리를 Java로 type-safe하게 개발할 수 있도록 지원하는 프레임워크로 쿼리 문장에 오타가 있을 시 컴파일 시점에 오류를 확인할 수 있다.
- Q타입은 컴파일 시점에 자동 생성되므로 버전관리(GIT)에 포함하지 않는 것이 좋기에 해당 디렉토리는 .gitignore를 통해서 포함하지 않도록 설정해야한다.
- 동적 쿼리 작성 시 BooleanBuilder를 사용해서 편리한 동적 쿼리를 작성 가능하다.
- 쿼리 조건을 부분적으로 모듈화해서 코드를 재사용할 수 있다.
출처 : [인프런 김영한 스프링 DB 2편 - 데이터 접근 활용 기술]
https://www.inflearn.com/course/%EC%8A%A4%ED%94%84%EB%A7%81-db-2/dashboard
스프링 DB 2편 - 데이터 접근 활용 기술 강의 | 김영한 - 인프런
김영한 | 백엔드 개발에 필요한 DB 데이터 접근 기술을 활용하고, 완성할 수 있습니다. 스프링 DB 접근 기술의 원리와 구조를 이해하고, 더 깊이있는 백엔드 개발자로 성장할 수 있습니다., 백엔드
www.inflearn.com
'Spring > [인프런 김영한 스프링 DB 2편 - 데이터 접근 활용 기술]' 카테고리의 다른 글
[인프런 김영한 스프링 DB 2편 - 데이터 접근 활용 기술] 스프링 트랜잭션 이해 (1) | 2024.11.29 |
---|---|
[인프런 김영한 스프링 DB 2편 - 데이터 접근 활용 기술] 데이터 접근 기술 - 활용 방안 (2) | 2024.11.27 |
[인프런 김영한 스프링 DB 2편 - 데이터 접근 활용 기술] 데이터 접근 기술 - 스프링 데이터 JPA (0) | 2024.11.26 |
[인프런 김영한 스프링 DB 2편 - 데이터 접근 활용 기술] 데이터 접근 기술 - JPA (1) | 2024.11.23 |
[인프런 김영한 스프링 DB 2편 - 데이터 접근 활용 기술] 데이터 접근 기술 - MyBatis (1) | 2024.11.21 |