본문 바로가기
Spring/JPA

@ManyToOne 연관관계에서 부모 엔터티를 등록할 때 프록시 호출을 통해 JPA 최적화 하기

by 흑시바 2024. 10. 22.

@ManyToOne 연관관계에서 findById()와 getOne()은 JPA(Java Persistence API)에서 엔티티를 조회할 때 사용하는 메서드이다. 이 두 메서드는 각각 다른 방식으로 엔티티를 조회하며, 사용하는 경우도 다르다. 두 메서드의 차이점과 사용 예시 및 최적화 방법에 대해 알아보자.

findById() 특징

내부적으로 EntityManager의 find()를 사용하며 영속성 컨텍스트, 2차 캐시, DB로 순서로 엔터티를 반환한다. 해당 메서드를 호출하는 경우 SELECT 쿼리가 발생한다.

 

1. 즉시 로딩 (Eager Loading)

findById()는 즉시 데이터베이스 쿼리를 실행하여 엔티티를 조회한다.
데이터베이스에서 해당 엔티티를 즉시 가져오기 때문에, 반환된 객체는 완전히 초기화된 상태이다.

 

2. Optional 반환

findById()는 Optional<T>를 반환한다. 이는 조회된 엔티티가 존재하지 않을 경우 null 대신 빈 Optional을 반환하여 NPE(NullPointerException)를 방지할 수 있다.

 

3. 예외 처리

엔티티가 존재하지 않을 경우 예외를 던지지 않고 빈 Optional을 반환한다.

 

사용하는 경우

 

- 엔티티가 존재하지 않을 가능성을 염두에 두고, 안전하게 조회하고자 할 때 사용한다.
- 즉시 데이터베이스에서 엔티티를 가져와야 할 때 사용한다.
- 조회된 엔티티가 반드시 존재해야 하는 경우가 아닌 경우에 사용한다.

 

Optional<MyEntity> entityOptional = myEntityRepository.findById(id);
if (entityOptional.isPresent()) {
    MyEntity entity = entityOptional.get();
    // 엔티티 사용
} else {
    // 엔티티가 존재하지 않을 때의 처리
}

getOne() 특징

내부적으로 EntityManager의 getOne()를 사용하며 하이버네이트 프록시 객체를 반환한다. 이는 실제 엔터티 타입과 다르며, 자식 엔터티가 부모에 대한 참조와 함께 등록되는 경우에 유용하게 사용할 수 있다.

 

1. 지연 로딩 (Lazy Loading)

getOne()은 데이터베이스 쿼리를 즉시 실행하지 않고, 프록시 객체를 반환한다.
실제 엔티티가 필요할 때 (예: 엔티티의 속성에 접근할 때) 데이터베이스 쿼리가 실행된다.

 

2. 프록시 반환

getOne()은 프록시 객체를 반환한다. 이는 엔티티의 실제 데이터가 필요할 때까지 데이터베이스 접근을 지연시킨다.

 

3. 예외 처리

 

엔티티가 존재하지 않을 경우 EntityNotFoundException을 던진다.

 

사용하는 경우


- 엔티티의 실제 데이터가 필요하지 않을 때 (예: 단순히 엔티티의 ID만 필요할 때) 사용한다.
- 성능 최적화를 위해 데이터베이스 접근을 지연시키고자 할 때 사용한다.
- 엔티티가 반드시 존재한다고 확신할 수 있을 때 사용한다.

 

try {
    MyEntity entity = myEntityRepository.getOne(id);
    // 엔티티 사용 (이 시점에서 데이터베이스 쿼리가 실행될 수 있음)
} catch (EntityNotFoundException e) {
    // 엔티티가 존재하지 않을 때의 처리
}

결론

getOne()은 자식 엔터티가 부모에대한 참조와 함께 등록될 때 유용하다. 해당 상황에서 DB로부터 엔터티를 가져오는 것은 성능 저하를 가지며, 하이버네이트가 초기화되지 않은 프록시에 대한 외래키 값을 설정할 수 있기 때문에 무의미하다.

댓글