내일배움캠프 80일차(QueryDSL사용)
오늘은 프로젝트에 QueryDSL을 적용하는 작업을 한다.
QueryDsl 사용을 위해 세팅하는 과정을 기록해 두겠다.
QueryDSL 사용을 위해 우선 다음 코드를 build.gradle의 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"
build를 누른 후 Gradle>Tasks>other>compilJava 를 클릭해 QClass를 생성한다.
만들어진 QClass를 삭제하고 싶을 땐 Gradle>Tasks>build>clean을 클릭하면 된다.
QueryDsl을 사용하기 위해 QuerydslConfiguration 파일을 생성한다.
@Configuration
public class QuerydslConfiguration {
@PersistenceContext
private EntityManager entityManager;
@Bean
public JPAQueryFactory jpaQueryFactory(){
return new JPAQueryFactory(entityManager);
}
}
QueryDsl을 사용하기 위한 Repository 구조를 잡는다.
여기서는 JpaQueryFactory를 주입받는 방식을 사용한다.
@Repository
@RequiredArgsConstructor
public class FestivalRepositoryCustom {
private final JPAQueryFactory queryFactory;
}
세팅하는 과정은 여기까지다. 이 밑으로는 QueryDsl을 사용하는 과정에서 발생한 문제와 그 해결을 기록하겠다.
문제1
order by count () 를 QueryDsl에서 사용하기 위해 인터넷 글을 참고해 다음과 같이 작성했다.
NumberPath<Long> aliasQuantity = Expressions.numberPath(Long.class, "quantity");
public List<Festival> findTop3Festival(){
reviews.count().as(aliasQuantity);
return queryFactory
.select(qFestival)
.from(qFestival)
.leftJoin(qFestival.reviews, reviews)
.groupBy(qFestival.id)
.orderBy(aliasQuantity.desc())
.limit(3)
.fetch();
}
그랬더니 postman에서 다음과 같은 오류 메세지가 떴다.
"org.hibernate.query.SemanticException: Could not interpret path expression 'quantity'"
numberPath안에 "quantity"대신 무언가 의미가 있는 문자를 넣어야겠다고 생각하고 "id"로 바꾸어 입력해 보았다.
그랬더니 다음과 같은 오류 메세지가 떴다.
"org.hibernate.query.sqm.InterpretationException: Error interpreting query [select f\nfrom Festival f\n left join f.reviews as r\ngroup by f.id\norder by id desc]; this may indicate a semantic (user query) problem or a bug in the parser [select f\nfrom Festival f\n left join f.reviews as r\ngroup by f.id\norder by id desc]"
일단 ""안에 적절한 문자를 넣어야 하는 것은 맞는 것 같다. 그리고 ""안의 문자가 orderBy로 들어가는 것 같다.
그런데 의외로 간단한 방법으로 해결이 되었다. 이런저런 방법을 찾아보던 중 그냥 .count()함수를 썼는데 실행에 성공했다!
기쁘지만 약간 허무했다...
하지만 위의 방법도 다른 상황에서는 유용하게 쓰일 수 있으니 기억해두기로 하였다.
아래는 이전에 사용했던 JPA문과 새로 작성한 QueryDsl문을 비교한 것이다.
JPA문
@Query(value = "select f.* \n"
+ "from festivals f\n"
+ "left join reviews r on f.id = r.festival_id\n"
+ "group by f.id\n"
+ "order by count(r.festival_id) desc\n"
+ "limit 3", nativeQuery = true)
List<Festival> findTop3Festival();
QueryDsl문
public List<Festival> findTop3Festival(){
return queryFactory
.select(qFestival)
.from(qFestival)
.leftJoin(qFestival.reviews, reviews)
.groupBy(qFestival.id)
.orderBy(reviews.festival.count().desc())
.limit(3)
.fetch();
}
기술면접 질문과 답
OAuth에 대해서 설명해주세요.
OAuth란 외부 서비스에서도 인증을 가능하게 하고 그 서비스의 API를 이용하게 해주는 것을 말합니다. 개인정보를 여러 곳에 입력하면 피싱에 둔감해지고, 애플리케이션이 안전하다는 보장이 없기 때문에 보안에 취약했습니다. 따라서 인증과 인가를 부여하는 요구를 만족시키기 위해 탄생했습니다. 클라이언트의 주도로 접근 요청이 사용됩니다.