본문 바로가기
Back-end/JPA 개념

API 조회 성능 최적화 - Entity 직접 노출 방식

by devraphy 2022. 5. 28.

- 이번 포스팅부터 단일 객체를 조회하는 API 성능을 최적화 하는 방식에 대해서 알아 볼 예정이다.

- 여기서 단일 객체란 Many To One 또는 One To One 관계를 가지는 객체를 의미한다. 

- 단일 객체를 조회하는 방식에는 Entity 직접 노출, DTO 변환, DTO 직접 사용 방식이 있다.

- 이에 대해 하나씩 알아보자.

 

1. Entity 직접 노출 방식의 문제점과 해결방법

- 결론부터 말하면, 이 방식은 사용하지 않는다.

- Entity를 직접 노출하는 방식은 Entity의 내용 변동이 있는 경우, API 스펙에도 변경사항이 발생하기 때문이다.

- 즉, API 스펙에 영향을 끼치는 구조이므로 사용하지 않는다. 

- 다만, Entity 직접 노출 방식을 사용하지 않는 이유에 대해서 이해할 수 있다. 

 

 

a) 양방향 관계와 무한 루프

- 양방향 연관 관계를 형성하는 객체를 조회할 때에는 무한 루프가 발생한다.

- 예를 들어, 객체 A와 B가 양방향 연관 관계라고 해보자. 

- 객체 A의 값을 조회하는 경우, 객체 A를 타고 객체 B에 들어간다. 그리고 다시 객체 B 내부에서 객체 A를 타고 들어간다.

- 이 과정이 반복되면서 무한 루프를 생성하게 된다. 

 

 

b) @JsonIgnore

- 양방향 관계 조회 시 발생되는 무한 루프를 예방하기 위해서 @JsonIgnore를 사용한다.

- 양방향 관계 중 한쪽 필드에 @JsonIgnore를 부착하여 무한 루프를 방지하는 것이다.

- 객체 A를 조회한다면 일반적으로 객체 B 내부의 양방향 관계 필드에 @JsonIgnore를 부착한다. 

 

 

c) @JsonIgnore의 문제점

- 양방향 관계라는 이름 그대로, 양쪽에서 조회하기 위해 형성된 관계다.

- 서비스의 기능에 따라 양방향 관계를 맺더라도 단방향의 조회 API만을 필요로 할 수 있다.

- 그러나 양방향 조회 API를 필요로 하는 경우, @JsonIgnore의 사용은 문제가 된다.

- @JsonIgnore가 부착된 필드는 애초에 조회 대상에서 제외되기 때문이다. 

- 이 문제의 해결책으로 Hibernate5 Module 라이브러리를 사용한다. 

 

 

d) Hibernate5 Module 사용 예시 - 연관 객체 제외 

- 우선 Gradle과 같은 빌드 자동화 도구의 설정 파일에 Hibernate5 Module을 설치한다.

 

- 연관 객체의 값을 필요로 하지 않는 경우, 다음과 같이 사용한다. 

@SpringBootApplication
public class JpabookApplication {

	public static void main(String[] args) {
		SpringApplication.run(JpabookApplication.class, args);
	}

	@Bean
	Hibernate5Module hibernate5Module() {
		return new Hibernate5Module();
	}
}

클릭하면 확대됩니다.

 

- 위의 사진처럼, 연관 객체의 값에는 null이 들어간 것을 확인할 수 있다.

- 연관 객체는 기본적으로 LAZY를 사용하기 때문에 Proxy 객체가 할당되므로 Null 값으로 표현된다.

 

 

e) Hibernate5 Module 사용 예시 - 연관 객체 포함

- 연관 객체의 값까지 조회하는 경우, 다음과 같이 사용한다. 

@SpringBootApplication
public class JpabookApplication {

	public static void main(String[] args) {
		SpringApplication.run(JpabookApplication.class, args);
	}

	@Bean
	Hibernate5Module hibernate5Module() {
		Hibernate5Module hb = new Hibernate5Module();
		hb.configure(Hibernate5Module.Feature.FORCE_LAZY_LOADING, true);
		return hb;
	}
}

- 위의 코드에서 사용된 옵션은 강제적으로 LAZY 로딩을 실행시킨다. 

 

 

- 위의 사진처럼, 모든 연관 객체의 데이터까지 조회되는 것을 확인할 수 있다.

 

 

f) Hibernate5 옵션 없이 Lazy 실행하는 방법

- Lazy를 실행시키는 방법은 Lazy가 걸려있는 필드의 데이터를 직접 호출하는 것이다.

- 객체에 접근하여 직접 해당 필드를 호출하는 방식으로 다음과 같이 코드를 작성한다.

@GetMapping("api/v1/simple-orders")
    public List<Order> ordersV1() { // Entity 노출 방식
        List<Order> all = orderRepository.findAllByString(new OrderSearch());

        // Hibernate5 옵션(Force_Lazy_Loading) 없이 Lazy 로딩 시키는 방법
        // => LAZY 옵션이 걸려있는 데이터를 직접 호출한다.
        for(Order order : all) {
            order.getMember().getName();
            order.getDelivery().getAdderss();
        }
        return all;
    }

댓글