엔티티 직접 노출 시 문제점

컴공생의 코딩 일기·2023년 1월 30일
0

JPA

목록 보기
12/14
post-thumbnail

엔티티 직접 노출 시 문제점

엔티티를 API 컨트롤러에 직접 노출하면 안된다. 직접 노출할 경우 다음과 같은 문제가 발생한다.

1. 무한 루프 발생 (해결 방법: @JsonIgnore 사용)

// APi Controller
private final OrderRepository orderRepository;
@GetMapping("/api/v1/simple-orders")
    public List<Order> ordersV1(){
        List<Order> all = orderRepository.findAllByString(new OrderSearch());
        return all;
    }

Api 컨트롤러 클래스에서 Order 엔티티 클래스로 데이터를 받은 후 직접 노출한 코드

이대로 실행할 경우 첫번째 문제로 무한루프가 발생한다.



Order 엔티티 클래스에 Member와 Member 클래스 엔티티에 List<Order>가 서로 호출하고 있기 때문에 무한루프가 발생한다.

해결 방법 (@JsonIgnore)


@JsonIgnore 어노테이션을 사용하려는 엔티티 클래스 반대편 엔티티 클래스에 지정해주면 된다.

2. 객체 타입 오류 (해결 방법: Hibernate5Module 빈 등록)

@JsonIgnore 어노테이션으로 무한루프 문제를 해결해도 아래와 같은 문제가 발생한다.

이 문제는 Order 엔티티 클래스에 Member가 지연로딩으로 되어 있기 때문에 new Member() 로 객체가 초기화 되는게 아니라 new ProxMember() 객체로 초기화 된다. 정확히는 new ByteBuddyInterceptor() 객체로 초기화 된다. 그렇기 때문에 오류가 발생한다. 이 문제를 해결하기 위해서는 Hibernate5Module 객체를 빈에 등록해줘야 한다.

문제 해결 (Hibernate5Module)

  • 스프링 부트 3.0 미만: Hibernate5Module
  • 스프링 부트 3.0 이상: Hibernate5JakartaModule

build.gradle 에 다음 라이브러리를 추가

  implementation 'com.fasterxml.jackson.datatype:jackson-datatype-hibernate5'

SpringBootApplication 에 Hibernate5Module를 빈으로 등록

@SpringBootApplication
public class JpashopApplication {

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

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

기본적으로 초기화된 프록시 객체만 노출하고 초기화 되지 않은 프록시 객체는 노출하지 않는다.

실행은 되지만 프록시 객체는 null 값으로 초기화 된다. (지연 로딩이 일어나지 않는다.)

지연 로딩 실행 방법


지연 로딩을 실행하기 위한 방법으로 Hibernate5Module 빈 설정에 위와 같은 설정을 해주면 된다. 하지만 이러한 방법은 모든 지연 로딩으로 설정된 엔티티를 실행 하기 때문에 필요하지 않는 엔티티도 실행되는 문제가 발생한다 그렇기 때문에 Hibernate5Module에서 설정하는 것 보다 아래와 같은 방법으로 필요한 엔티티만 지연로딩 할 수 있게 해주는게 바람직하다.

주위: 지연 로딩(LAZY)을 피하기 위해 즉시 로딩(EARGR)으로 설정하면 안된다. 즉시 로딩 때문에 연관관계가 필요 없는 경우에도 데이터를 항상 조회해서 성능 문제가 발생할 수 있다. (N + 1 문제 등) 즉시 로딩으로 설정하면 성능 튜닝이 매우 어려워진다.
항상 지연로딩을 기본으로 하고, 성능 최적화가 필요한 경우 패치조인(fetch join)을 사용하자

profile
더 좋은 개발자가 되기위한 과정

0개의 댓글