[JPA 활용2 스터디] week 7
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 생성자 변경시 사용했음)