동적쿼리를 적용한 이유
Query Dsl을 적용하면서 너무나 많은 중복되고 반복적인 코드가 발생하였고
이러한 로직이 Controller와 service단에서 존재했기 때문에 다른 핵심로직의 가독성을 해칠우려가 있다고
판단했고 이를 개선하기 위해서 동적쿼리를 적용하기로 했다.
Query Dsl 의 장점
- 여러 장점 보기
- 문자가 아닌 코드로 쿼리를 작성함으로써, 컴파일 시점에 문법 오류를 쉽게 확인할 수 있다.
- 자동 완성 등 IDE의 도움을 받을 수 있다.
- 동적인 쿼리 작성이 편리하다.
- 쿼리 작성 시 제약 조건 등을 메서드 추출을 통해 재사용할 수 있다.
근데 그냥 Query Dsl의 장점은
가독성이 좋은 쿼리문 / 동적 쿼리
2가지로 보면 된다.
준비하기
StringUtils 라이브러리만 있으면 된다. 이게 왜 있어야하는지는 아래에 설명하겠음 !
// import문
import org.apache.commons.lang3.StringUtils;
// build.gradle
implementation group: 'org.apache.commons', name: 'commons-lang3', version: '3.12.0'
StringUtils이란?
String 문자열과 관련된 많은 일들을 해주는 라이브러리로 사용 가능한 함수들은 아래 링크 참고
https://velog.io/@dingdoooo/JavaStudy-StringUtils-문자열-작업-관련-기능-Library
[JavaStudy] 3. StringUtils - 문자열 작업 관련 기능 Library
StringUtils? StringUtils를 사용하면 java.lang.String이 즉시 제공하는 작업을 보완/ 확장하는 인력의 작업들을 수행할 수 있다. 문자열이 공백인지, 비어있는지, 소문자인지 ,대문자인지, 영숫자 인지 확
velog.io
StringUtils을 왜 써야하나?
파라미터 값으로 null을 주더라도 절대 NullPointException을 발생시키지 않음.
(null이 입력되는 경우, 메소드에 따라 알맞은 결과를 리턴.)
⇒ 동적쿼리를 구현하기 위해서는 다양한 조건값을 줘야하는데 null값이 나왔을때
NullPointException이 떠버리면 시스템이 죽어버리기 때문에 구현할 수가 없다
즉 null값에 대한 처리가 간편하기 때문에 단지 이 이유때문에 StringUtils을 쓴다
또한 아래에서 설명할 BooleanExpression과 함께 사용해서 가독성을 높이는 역할을 한다.
구현
// config 패키지
@Data
public class SearchCondition {
private Long storeId; // DB에 저장되는 id
private String address; // 일반 주소
private String roadNameAddress; // 도로명 주소
private int postNumber; // 우편 번호
private String storeName; // 가게 이름
private String typeOfBusiness; // 업종
private double xCoordinate; // 위도(x좌표)
private double yCoordinate; // 경도(y좌표)
private double starScore; // 별점
private int reviewCnt; // 리뷰 갯수
}
SearchCondition을 생성하고 검색 조건이 되는 필드들을 생성하고 이를 한번에 주고 받게 된다.
ex) storeName을 검색할 경우
SearchCondition
(storeId=null, address=null, roadNameAddress=null, postNumber=0, storeName=장안순대국밥, typeOfBusiness=null, xCoordinate=0.0, yCoordinate=0.0, starScore=0.0, reviewCnt=0)
Controller
넘겨줄 매개변수를 사진과 같이 변경
service
service에서도 동일하게 변경
RepositoryCustom
repositoryCustom을 위 사진과 같이 하나로 줄일 수 있다.
RepositoryImpl
where절에서 함수를 따로 만들어 다양한 조건으로 들어 갈 수 있게끔 해줬다.
하지만 전부 다 실행되지는 않는다. 왜냐하면
StringUtils에 의해서 isEmpty일 경우 null을 반환하게 되고 StringUtils는 NullPointException을 띄우지 않기
때문에 null값이 그대로 where로 넘어가게 된다.
근데 넘어가는 과정에서 BooleanExpression으로 넘어가기 때문에 해당 값은 where절에서 제외된다.
BooleanExpression은 null을 리턴받을 경우 제외시키는 특징이 있기 때문이다.
그렇게 되면 아까 검색해서 얻은
SearchCondition (
storeId=null, address=null, roadNameAddress=null, postNumber=0, storeName=장안순대국밥, typeOfBusiness=null, xCoordinate=0.0, yCoordinate=0.0, starScore=0.0, reviewCnt=0
)
condition에 담겨져 있는 값들에 따라서 값이 들어 있는 조건만 where에 걸리게 되면서 쿼리가 동작하게 된다.
문제
SearchCondition (
storeId=null, address=null, roadNameAddress=null, postNumber=0, storeName=장안순대국밥, typeOfBusiness=null, xCoordinate=0.0, yCoordinate=0.0, starScore=0.0, reviewCnt=0
)
가게 이름 일치, 도로명 주소, 가게 이름, 업종과 같이 조건값이 명확한 경우
condition을 통해 넘어오는 값도 한가지 해당하는 검색조건도 한가지이지만
starScore와 reviewCnt의 경우에는 한가지의 값으로 두가지의 경우를 처리해야하고
검색어가 없는 검색어 없이 탭의 4가지 조건은 아예 조건값조차 없는데 이걸 어떻게 판단할까 라는 고민을 했다.
이 고민은 각각의 검색항목들은 html에서 url로 구분하고 있기 때문에 그 구분하고 있는 url을 받아와서
처리할 수 있도록 getRequestURI 메소드를 활용하기로 했다
<optgroup label="=== 검색어 지정 ===">
<option name="test" value="/api/search/storeName/?storeName=">가게 이름 일치</option>
<option name="test" value="/api/search/roadAddressInclude/?roadNameAddress=">도로명 주소</option>
<option name="test" value="/api/search/storeNameInclude/?storeNameInclude=">가게 이름
</option>
<option name="test" value="/api/search/Business/?typeOfBusiness=">업종</option>
<option name="test" value="/api/search/StarScoreHigh/?starScore=">평점 n점이상</option>
<option name="test" value="/api/search/StarScoreLow/?starScore=">평점 n점이하</option>
<option name="test" value="/api/search/ReviewHigh/?reviewCnt=">리뷰 n개이상</option>
<option name="test" value="/api/search/ReviewLow/?reviewCnt=">리뷰 n개이하</option>
</optgroup>
<optgroup label="=== 검색어 없이 ===">
<option name="test" value="/api/search/ReviewASC">리뷰 적은순</option>
<option name="test" value="/api/search/ReviewDESC">리뷰 많은순</option>
<option name="test" value="/api/search/StarScoreASC">평점 낮은순</option>
<option name="test" value="/api/search/StarScoreDESC">평점 높은순</option>
</optgroup>
'legacy > Pin-Table 성능 개선 기록' 카테고리의 다른 글
검색 성능 개선 #6 방향성에 대한 고민2 (0) | 2023.02.09 |
---|---|
검색 성능 개선 #5 DynamicSQL 코드 개선 (0) | 2023.02.09 |
검색 성능 개선 #3 QueryDsl 구현 (0) | 2023.02.09 |
검색 성능 개선 #2 JPA findBy 메소드 (0) | 2023.02.09 |
검색 성능 개선 #1 방향성에 대한 고민 (0) | 2023.02.09 |