legacy/Pin-Table 성능 개선 기록
검색 성능 개선 #3 QueryDsl 구현
3hoon
2023. 2. 9. 17:06
query dsl 기술적인 선택 이유
findBy 메소드로는 다양한 조건의 검색기능을 구현하기에는
가독성 측면에서 좋지 않다는 점과 제한적인 조건이 걸렸다.
네이티브 쿼리도 고려를 했으나 쿼리를 활용할 것이라면은
쿼리를 코드로 작성할 수 있고 컴파일 에러를 찾아 낼 수 있다는
장점도 가지고 있는 Query Dsl을 적용하기로 했다.
쿼리를 자바 코드로 작성할 수 있게 도와주는 기술로
JPA로는 어려운 복잡한 쿼리나 동적쿼리까지 해결할 수 있는 장점이 있다.
또한 문법의 오류를 컴파일시에 찾아 낼 수 있다는 장점을 가지고 있다.
1. Query Dsl 특징
1. 쿼리를 코드로 작성 가능 (ide의 자동완성 기능을 사용할 수 있다)
2. 컴파일시 문법 오류를 찾아낼 수 있음
3. 동적 쿼리 구현 가능
4. 가독성 향상 가능
* 동적쿼리(Dynamic SQL) : 특정 조건들이나 상황에 따라 변경되는 쿼리
* 정적쿼리(Static SQL) : 어떤 조건 또는 상황에도 변경되지 않는 쿼리
2. Query Dsl 적용
config 패키지
package com.example.pirate99_final.map.config;
import com.querydsl.jpa.impl.JPAQueryFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
@Configuration
public class QuerydslConfiguration {
@PersistenceContext
private EntityManager entityManager;
@Bean
public JPAQueryFactory jpaQueryFactory() {
return new JPAQueryFactory(entityManager);
}
}
bulid.gradle
// query dsl 버전
buildscript {
ext {
queryDslVersion = "5.0.0"
}
}
plugins{
id 'java'
id "com.ewerk.gradle.plugins.querydsl" version "1.0.10"
}
dependencies {
implementation "com.querydsl:querydsl-jpa:${queryDslVersion}"
implementation "com.querydsl:querydsl-apt:${queryDslVersion}"
annotationProcessor "com.querydsl:querydsl-apt:${queryDslVersion}"
}
//querydsl 추가 시작
def querydslDir = "$buildDir/generated/querydsl"
querydsl {
jpa = true
querydslSourcesDir = querydslDir
}
sourceSets {
main.java.srcDir querydslDir
}
configurations {
querydsl.extendsFrom compileClasspath
}
compileQuerydsl {
options.annotationProcessorPath = configurations.querydsl
}
QEntity 구현
Gradle -> other -> compileQueryDsl을 실행하면
QEntity
package com.example.pirate99_final.map.entity;
import static com.querydsl.core.types.PathMetadataFactory.*;
import com.querydsl.core.types.dsl.*;
import com.querydsl.core.types.PathMetadata;
import javax.annotation.processing.Generated;
import com.querydsl.core.types.Path;
/**
* QNaver is a Querydsl query type for Naver
*/
@Generated("com.querydsl.codegen.DefaultEntitySerializer")
public class QNaver extends EntityPathBase<Naver> {
private static final longserialVersionUID= 1431852996L;
public static final QNavernaver= new QNaver("naver");
public final StringPath address = createString("address");
public final NumberPath<Long> id = createNumber("id", Long.class);
public final NumberPath<Integer> postnumber = createNumber("postnumber", Integer.class);
public final NumberPath<Integer> reviewcnt = createNumber("reviewcnt", Integer.class);
public final StringPath roadnameaddress = createString("roadnameaddress");
public final NumberPath<Double> starscore = createNumber("starscore", Double.class);
public final StringPath storename = createString("storename");
public final StringPath typeofbusiness = createString("typeofbusiness");
public final NumberPath<Double> xcoordinate = createNumber("xcoordinate", Double.class);
public final NumberPath<Double> ycoordinate = createNumber("ycoordinate", Double.class);
public QNaver(String variable) {
super(Naver.class,forVariable(variable));
}
public QNaver(Path<? extends Naver> path) {
super(path.getType(), path.getMetadata());
}
public QNaver(PathMetadata metadata) {
super(Naver.class, metadata);
}
}
3. Query Dsl 구현
RepositoryCustom
package com.example.pirate99_final.map.repository;
import com.example.pirate99_final.map.entity.Naver;
import java.util.List;
public interface NaverRepositoryCustom {
Naver findByStoreName(String storeName);
List<Naver> findByStoreNameInclude(String storeName);
List<Naver> findByroadAddressInclude(String roadNameAddress);
List<Naver> findByBusiness(String typeOfBusiness);
List<Naver> OrderByStarScore();
List<Naver> OrderByStarScoreDESC();
List<Naver> OrderByReview();
List<Naver> OrderByReviewDESC();
List<Naver> BetweenStarScoreHigh();
List<Naver> BetweenStarScoreLow();
List<Naver> BetweenReviewHigh();
List<Naver> BetweenReviewLow();
}
RepositoryImpl
package com.example.pirate99_final.map.repository;
import com.example.pirate99_final.map.entity.Naver;
import com.example.pirate99_final.map.entity.QNaver;
import com.querydsl.core.types.dsl.BooleanExpression;
import com.querydsl.jpa.impl.JPAQueryFactory;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Repository;
import org.apache.commons.lang3.StringUtils;
import java.util.List;
@Repository
@RequiredArgsConstructor
public class NaverRepositoryImpl implements NaverRepositoryCustom {
private final JPAQueryFactory queryFactory;
public Naver findByStoreName(String storeName) {
QNaver naver = QNaver.naver;
Naver findByStoreName = queryFactory
.selectFrom(naver)
.where(naver.storename.eq(storeName))
.fetchOne();
return findByStoreName;
}
public List<Naver> findByStoreNameInclude(String storeName) {
QNaver naver = QNaver.naver;
List<Naver> StoreNameInclude = queryFactory
.selectFrom(naver)
.limit(10)
.where(naver.storename.contains(storeName))
.fetch();
return StoreNameInclude;
}
public List<Naver> findByroadAddressInclude(String roadNameAddress) {
QNaver naver = QNaver.naver;
List<Naver> roadAddressInclude = queryFactory
.selectFrom(naver)
.limit(10)
.where(naver.roadnameaddress.contains(roadNameAddress))
.fetch();
return roadAddressInclude;
}
public List<Naver> findByBusiness(String typeOfBusiness) {
QNaver naver = QNaver.naver;
List<Naver> businessType = queryFactory
.selectFrom(naver)
.limit(10)
.where(naver.typeofbusiness.eq(typeOfBusiness))
.fetch();
return businessType;
}
public List<Naver> OrderByStarScore() {
QNaver naver = QNaver.naver;
List<Naver> starScoreASC = queryFactory
.selectFrom(naver)
.limit(10)
.orderBy(naver.starscore.asc())
.fetch();
return starScoreASC;
}
public List<Naver> OrderByStarScoreDESC() {
QNaver naver = QNaver.naver;
List<Naver> starScoreDESC = queryFactory
.selectFrom(naver)
.limit(10)
.orderBy(naver.starscore.desc())
.fetch();
return starScoreDESC;
}
public List<Naver> OrderByReview() {
QNaver naver = QNaver.naver;
List<Naver> reviewASC = queryFactory
.selectFrom(naver)
.limit(10)
.orderBy(naver.reviewcnt.asc())
.fetch();
return reviewASC;
}
public List<Naver> OrderByReviewDESC() {
QNaver naver = QNaver.naver;
List<Naver> reviewDESC = queryFactory
.selectFrom(naver)
.limit(10)
.orderBy(naver.reviewcnt.desc())
.fetch();
return reviewDESC;
}
public List<Naver> BetweenStarScoreHigh() {
QNaver naver = QNaver.naver;
List<Naver> BetweenStarScoreHigh = queryFactory
.selectFrom(naver)
.limit(10)
.where(naver.starscore.between(4, 5))
.orderBy(naver.starscore.desc())
.fetch();
return BetweenStarScoreHigh;
}
public List<Naver> BetweenStarScoreLow() {
QNaver naver = QNaver.naver;
List<Naver> BetweenStarScoreLow = queryFactory
.selectFrom(naver)
.limit(10)
.where(naver.starscore.between(0, 2))
.orderBy(naver.starscore.desc())
.fetch();
return BetweenStarScoreLow;
}
public List<Naver> BetweenReviewHigh() {
QNaver naver = QNaver.naver;
List<Naver> BetweenReviewHigh = queryFactory
.selectFrom(naver)
.limit(10)
.where(naver.reviewcnt.between(1000, 1000000))
.orderBy(naver.reviewcnt.desc())
.fetch();
return BetweenReviewHigh;
}
public List<Naver> BetweenReviewLow() {
QNaver naver = QNaver.naver;
List<Naver> BetweenReviewLow = queryFactory
.selectFrom(naver)
.limit(10)
.where(naver.reviewcnt.between(0, 10))
.orderBy(naver.reviewcnt.desc())
.fetch();
return BetweenReviewLow;
}
}