Code Review
안녕하세요 멘토님! :)
작성한 코드에 대해 부족한 점, 잘못된 점, 잘한 점 등 아낌없이 조언해주시면 감사드리겠습니다! 😊
코드 작성하면서 어려웠던 점
즉시 로딩과 지연로딩에 대해 배우는 시간을 가졌습니다.
Join과 Fetch Join의 차이에 대해 배우고, Fetch Join과 지연로딩과의 차이를 찾아 공부했습니다.
좋은 쿼리에 대해 생각해보는 시간을 가졌습니다.
✚ 코드 리뷰를 반영하여 2주차 과제를 개선했습니다. 😼
코드 리뷰시 중심적으로 리뷰해주셨으면 하는 부분
좋은 쿼리를 갖는 코드란?
제 생각으로는 하나의 작업을 수행할때 DB에 최소한의 쿼리를 날리는 것이라고 생각합니다.
이때 최소한의 쿼리를 날리면, 항상 그보다 많은 쿼리를 수행하는 것보다 짧은 시간이 걸리는지 궁금합니다.
(예를 들어 같은 작업을 수행했을때 inner query를 쓰거나 fetch join을 사용할경우 수행시간)
멘토님이 생각하시는 좋은 쿼리란 무엇인지 궁금합니다. 😄
Answer
효율적인 쿼리는 내가 원하는 데이터만 DB에서 조회하면서 쿼리를 최소로 실행하고 처리 시간이 적은것을 좋은 query라고 생각합니다. 최소한의 쿼리가 항상 짧지는 않습니다. 쿼리의 실행 계획과 인덱스가 잘되어있는지등 여러요소를 같이 봐야합니다.
지연로딩시 fetch join
저는 연관관계 객체의 필드 값까지 조회해야할때 fetch join을 사용했습니다. 그 이유는 @manytoone이기때문에 여러번 fetch join을 수행할 수 있고, N+1 문제를 해결할 수 있는 방법이기 때문입니다.
fetch join 이외에도 select 쿼리가 늘어나지만 연관관계의 객체를 미리 가져오는 방법도 있다고 들었습니다.
위의 경우에 fetch join이 좋은 방법이라고 생각하시는지 멘토님의 생각이 궁금합니다. (더 좋은 방법이 있다면 추천해주시면 감사하겠습니다!)
항상 감사합니다. 😌
Answer
A. 간단한 조인은 fetch join을 사용하며 쿼리가 복잡한 경우 querydsl을 사용하기도 합니다.
변경사항
1. 하드코딩으로 아이디를 넣기보다는 저장된 ID를 불러와서 유연하게 사용하면 좋다.
기존 코드
Optional<Cart> cartOptional = cartJPARepository.mFindById(1)
수정 코드
@Test
@DisplayName("3.주문하기 (장바구니 수정)")
public void update_cart_test() throws JsonProcessingException {
// given
Cart c = cartJPARepository.mFindFetchAll().get(0); //맨 처음 cart 가져오기
int id = c.getId();
// when
// select 쿼리 2번(join fetch 1번+ option의 Product 조회 1번) + update 쿼리 1번
c.update(10); //장바구니 수정
String responseBody = om.writeValueAsString(c); //직렬화하여 출력
System.out.println("테스트 : "+responseBody);
//then
Assertions.assertThat(c.getId()).isEqualTo(id);
Assertions.assertThat(c.getQuantity()).isEqualTo(10); //변경 값으로
}
그런데 궁금한 것이 생겼다.
@Test
@DisplayName("2. 개별 상품 상세 조회 : Lazy")
public void option_mFindByProductId_lazy_test() throws JsonProcessingException {
// given
Option option = optionJPARepository.findAll().get(0);
int id = option.getProduct().getId();
// when
List<Option> optionListPS = optionJPARepository.mFindByProductId(id); // Lazy, join fetch 사용해서 연관관계 객체 가져오기
System.out.println("json 직렬화 직전========================");
String responseBody = om.writeValueAsString(optionListPS);
System.out.println("테스트 : "+responseBody);
// then
}
위 코드를 보면 데이터가 존재하는지 보장하기 위해 option을 다 가져오고 맨 처음 하나를 가져오는 것이
맞는지 의문이 들었다.(굉장히 비효율적이기 때문)
질문해볼 생각이다.
2. flush를 하지 않아도 테스트가 가능하다.
if(cartOptional.isPresent()){
Cart c = cartOptional.get();
c.update(10); //장바구니 수정
em.flush(); //DB 반영
@DataJpaTest에서 EntityManager가 관리 대상 엔티티의 변경사항을 자동으로 flush해서 그렇다.
em.flush는 지워도 된다.
화이팅 !!
'Spring > 카테캠 - TIL' 카테고리의 다른 글
TIL [0726] : 5주차 강의 - 상품 목록, 상세보기, 장바구니 담기, 조회, 업데이트 (0) | 2023.07.26 |
---|---|
TIL [0725] : 5주차 강의 - 코드 리팩토링(GlobalExceptionHandler, AOP) (0) | 2023.07.25 |
카테캠 4주차 과제 중 문제 - 해결 (유효성 검사, Mockito 인자+anyInt, UserDetails 직접 주입) (0) | 2023.07.21 |
카카오테크캠퍼스 : 4주차 과제 (0) | 2023.07.19 |
4주차 강의 : DTO 유효성 검사, Custom Exception, Controller와 Service의 책임, OSIV (2) | 2023.07.19 |