JPA API

Haechan Kim·2022년 9월 12일
0

Spring

목록 보기
16/68

Member 엔티티의 @NotEmpty는 화면에서 필요한 프레젠테이션 계층.
프레젠테이션 계층 위한 검증 로직이 entity에 다 들어가있음.
-> 화면 validation 로직이 들어간 것.

api마다 필요 할수도 필요 없을 수도 있음.

entity 스펙을 name에서 userName으로 바꾼다면?
ㄴ api 스펙자체가 바뀌어 버림. api 동작 안함.

-> 문제는 엔티티를 손대서 api 스펙 자체가 변해버린 것.
엔티티는 여러곳에서 쓰임.
엔티티 바꿨다고 해서 엔티티 스펙 바뀌면 안됨.

지금은 엔티티랑 api 스펙이 1:1 매핑되어 있음.

-> API 스펙을 위한 별도의 DTO 만들어야 함.
-> api 만들 때 entity 파라미터로 받지 말자 !
엔티티 외부 노출도 X.

  • 회원 수정

수정시에는 가급적이면 변경 감지 쓰기

  • 회원 조회

templates - application.yaml

jpa:
      hibernate:
        ddl-auto: none # create: 앱 실행시 엔티티 다 지우고 다시 생성, none: drop하지 않고 게속 사용
  • 리스트로 반환하면 유연성 떨어짐.
    속성 하나 더 추가하는 경우
    ㄴ ex) 회원 조회하는데 count 속성을 추가하는 경우 배열로 반환하는 경우는 못하지만 객체 형태면 가능
    오브젝트 타입으로 껍데기를 씌워서 반환하자 !
@GetMapping("/api/v2/members")
public Result membersV2() { // 응답값 껍데기 클래스 Result
    List<Member> findMembers = memberService.findMembers(); // 가져와서 memberDto로 변환

    // 멤버 엔티티에서 이름 꺼내와서 dto로 넣고 변환
    List<MemberDto> collect = findMembers.stream()
            .map(m -> new MemberDto(m.getName()))
            .collect(Collectors.toList());// 리스트로 변환

    // -> list Member를 list MemberDto로 변환

    return new Result(collect);
    // return new Result(collect.size(), collect); // count 넣는 경우
}

@Data
@AllArgsConstructor
// 오브젝트 타입으로 반환하기 때문에 Result라는 껍데기 씌워 줌.
// 이런식으로 한번 감싸줘야 한다. 리스트를 바로 내면 json 배열 타입으로 나가버리기 때문에 유연성 떨어짐.
static class Result<T> { // 제네릭
    // private int count; // 이런식으로 바로 넣으면 됨.
    private T data;
}

엔티티 절대 외부에 직접 반환하지 말자 !!
항상 다 DTO로 바꾸자.

성능 문제 대부분 조회에서 발생.

  • 지연 로딩 (lazy)
    아직 db에서 조회한게 아님.
    lazy loading 갯수만큼 쿼리 반복해서 나감 - 성능 문제

  • fetch join
    실무에서 매우 자주 씀. 꼭 알아두기!!
    쿼리 하나만 길게 나감.

  • 쿼리 방식 선택 권장 순서

  1. 엔티티 dto로 변환하는 방법 선택.
  2. 필요 시 fetch join으로 성능 최적화.
  3. 그래도 안되면 dto 직접 조회 (재사용성 bad, api 스펙에 맞춰짐)

앞에서의 조회는 xToOne 관계. fetch join으로 최적화 할 수 있었음.
하지만 컬렉션 조회(일대다 조회)의 경우 fetch join 시 페이징 불가.

컬렉션 fetch join 시 일대다 조인이 발생하므로 데이터가 예측할 수 없이 증가한다.

일대다에서 1을 기준으로 페이징 하는것이 목적인데, 데이터는 다(N)를 기준으로 row가 생성됨.

  • ToOne관계(OneToOne, ManyToOne) 관계는 모두 fetch join. ToOne관계는 row 수 증가시키지 않으므로 페이징 쿼리에 영향 주지 않음.

  • 컬렉션은 지연 로딩으로 조회 (default_batch_fetch_size로 최적화 하자)

default_batch_fetch_size

  • Spring Data Jpa

memberRepository.find(), save() 등등 typeorm처럼 다 제공해줌.

findByName 같은 경우에도 이름 보고 알아서 만들어줌.
select m from member m where m.name = ? (jpql)

public interface MemberRepository extends JpaRepository<Member, Long> {

    // 이렇게만 하면 끝!!
    // 스프링 data jpa 가 알아서 다 만들어 줌.
    // select m from member m where m.name = ? (jpql)
    List<Member> findByName(String name);

}

실무에선 스프링, jpa, 스프링 데이터 jpa, 쿼리 dsl -> 생산성 향상.
하지만 스프링 데이터 jpa는 jpa 활용해서 이런 기능 제공할 뿐.
결국 jpa 잘 이해하는것이 중요.

0개의 댓글