개발/JPA

[JPA 활용2 스터디] week 7

Dahee Joy Cha 2022. 2. 6. 20:42

API 개발 기본

Controller에서 Entity를 바로 받거나 반환하면 안되는 이유

예) saveMember(@RequestBody @Valid Member member)  // Member는 Entity

1) 요청마다 Member 내 validation의 조건이 달라진다. 

    : 회원가입시 전화번호가 필수지만, 회원 수정시 전화번호는 null 가능. 

2) Entity의 column명 변경시, api의 스펙이 변경되는 문제 발생.   

3) parameter 파악 위해 Dto만 열어보면 되는데, Entiy 받으면 api 스펙 문서를 열어봐야함. 

-> 요청 파라메터/응답은 dto를 쓰자

4) 필요하지 않은 필드 (예. member의 order)도 가져오므로 성능 이슈 

 

참고: @Data 애노테이션 사용 유무

Entity -> 자제. 써도 Getter 정도만. 

Dto -> @Data  써도 크게 상관 x 

 

수정 api (PUT)

- 수정할 때는 가급적 변경 감지를 사용하자. 

- 커멘드와 쿼리는 분리하자

// Member를 반환하지 않는다. 커멘트성(update)만 유지. 
public void update(Long id, String name) {
	Member member = memberRepository.findOne(id);
    member.setName(name);
}

//"커멘드와 쿼리를 분리하라" 규칙 따른 controller 내부 로직
memberService.update(id, request.getName()); // 커멘트
Member findMember = memberService.findOne(id); // 쿼리
return new UpdateMemberResponse(findMember.getId(), findMember.getName());

 

조회 api (get)

- 테이블 변경 할 피요 없으니까, pplication.yml 내 ddl-auto는 none으로 바꾸고 스타트. 

- json 형태로 반환해야한다.  -> {로 시작해서 }로 끝나야함. array를 바로 반환하면 안됨. 

 

지연 로딩 & 조회 성능 최적화

xToOne

Order - Member 관계

문제점 1) 잭슨라이브러리에서 json 형성을 위해 ORder -> Member -> Order -> Member 로 가며 무한 루프 발생

-> 양방향에서 한쪽에 @JsonIgnore 적용

 

문제점 2) Order에서 member의 proxy 객체를 가짐. bytebuddy 오류 발생

-> 해결 방법 1. build.gradle에서 jackson-datatype-hibernate5 적용

-> 해결 방법 2. member.getOrder.getName을 controller 단에서 호출. (영속성 컨텍스트에 Entity 정보 로딩)

-> Entity 반환하지 않으면 생기지 않을 문제니까, 이런게 있다는 것만 알아두자 ^^

-> 본 문제 해결하기 위해 fetch에 EAGER 적용하지 말것. 

 

 

참고: note 

1) 반환 객체는 Result 이어야한다.  List라면 Result로 다시 바꿀것. 

2) dto에서 entity 의존하는 것은 괜찮다 (반대로, domain 객체에서 dto의존하는 것은 never)

@Data
class SimpleOrderDto {
	private Long orderId;
	// 필드변수 중략
    
    // Order Entity에 의존
	public SimpleOrderDto(Order order) {
		orderId = order.getId()
        // 중략
	}
}

 

지연로딩으로 인한 N+1 문제

- v2 조회 api에서 발생

- 이유: 쿼리 1 (ORDER 2건) -> 쿼리 2 (member, delivery 각각) ->  쿼리 2 (member, delivery 각각)  -> 총 5번

          : N+1 -> 1 + 회원 N + 배송 N

- 해결: fetch join으로 해결 (쿼리 1건) . 절대 EAGER로 해결하지 마라. (fetch조인은 실무에서 자주 사용!!)

 

v4의 개선점

- v4의 장점: select 절에서 내가 필요한 데이터만 가져옴

- v4의 단점

   : dto사용하지 않는 곳에선 쿼리 재사용 불가. ( cf. v3: 쿼리 재사용 가능)

   : api의 스펙이 repository에 들어간다. (찬반 분분. 강사님은 괜찮다고 생각한다고 함)

-> V3와 V4의 성능 차이는 크지 않다. (Select 컬럼 수는 네트워크 성능에 크게 영향 x. 보통 join에서 영향 큼)

 

** 이번 스터디 이후 TODO:

- 코드 처음부터 다시 작성해보기 

- column selection mode IntelliJ에서 사용해보기 (OrderSimpleQueryDto 생성자 변경시 사용했음)