실전! 코틀린과 스프링 부트로 도서관리 애플리케이션 개발하기

Ch04. 요구사항 추가(책 통계, QueryDSL) - 애플리케이션 대신 DB로 기능 구현

webmaster 2022. 11. 8. 00:08
728x90

다양한 SQL 그룹 함수

  • sum : 주어진 column의 합계를 계산한다.
  • avg : 주어진 column의 평균을 계산한다.
  • count : 개수를 센다
  • group by : 주어진 column을 기준으로 grouping 한다. -> 함수형 프로그래밍의 groupby와 유사하다.
  • order by : 주어진 column을 기준으로 정렬한다. -> 내림차순, 오름차순 지정할 수 있다.

애플리케이션 대신 DB로 기능 구현하기

UserLoanHistoryRepository

interface UserLoanHistoryRepository : JpaRepository<UserLoanHistory, Long> {
	//...
    fun countByStatus(status: UserLoanStatus): Long
}

BookService

@Transactional(readOnly = true)
fun countLoanedBook(): Int {
    //기능은 같지만 내부 동작이 아예 다르다.
    //1) 전체 데이터 쿼리 메모리 로딩 + size 2) count 쿼리 타입 변경
    //2번 기능이 더 좋다고 생각한다 -> 데이터가 많아질수록..  OOM이 생길수 있다
    return userLoanHistoryRepository.countByStatus(UserLoanStatus.LOANED).toInt() //숫자만 메모리에 올려 타입만 변경해준다
}
  • 이전 방식과 다르게 DB에서 Count 쿼리를 한 결과를 가지고  와서 타입만 변환하여 리턴한다.
  • 이전 기능에서는 전체 데이터를 쿼리로 가지고와 메모리에 로딩한 후, 애플리케이션에서 size를 측정하였고, 이번 방식은 DB에서 Count 쿼리를 바로 동작시켜 값만 받아와서 변환해준다.
  • 2번째 방법이 좀 더 좋은 거 같다 -> 모든 데이터를 메모리에 올리게 되면 애플리케이션을 부하가 심해지고, 메모리가 full 될 수도 있다.

BookRepository

interface BookRepository : JpaRepository<Book, Long> {
	//...
    @Query("select new com.group.libraryapp.dto.book.request.BookStatResponse(b.type, COUNT(b.id)) from Book b " +
            "group by b.type")
    fun getStats(): List<BookStatResponse>
}

BookService

@Transactional(readOnly = true)
fun getBookStatistics(): List<BookStatResponse> {
    return bookRepository.getStats()
}
  • @Query를 사용해 JPQL을 작성할 수 있으며, 생성자를 통해 Projection을 지정할 수 있다 
    • 이때 반드시 dto는 풀 패키지 명을 적어야 한다.
  • group by 함수를 사용해 type으로 grouping하여 count를 추려왔다
  • 이전 방식보다 지금방식이 더 좋아 보인다 -> DB는 index를 걸거나 해서 최적화를 할 수 있기 때문이다
    • 단, 반드시 지금 방식이 좋은 것은 아니기 때문에 상황에 따라 적절한 방식을 선택해서 진행하는 방식으로 하자
728x90