백엔드 개발자

JPA 기본 정리 #3 본문

스프링/JPA

JPA 기본 정리 #3

임잠탱 2023. 9. 3. 03:21

N + 1 문제

  • JPA를 이용하여 객체지향적인 설계가 가능해지는데, 엔티티 안에 엔티티를 포함할 경우 한 번 엔티티를 호출하는 것이 해당 엔티티에 포함된 다른 엔티티까지 호출하게 되면서 쿼리가 한 번 혹은 그 이상 더 호출하는 문제가 생기게 된다.
  • JPQL을 사용할 때 발생하게 되는데(jpa에서 지원하는 find는 최적화를 통해 join으로 호출한다) JPQL을 SQL로 변환하여 호출하고 그 안에 필요한 값들을 추가로 호출하게 되는 것이다.
  • 모든 값이 다 필요한 경우라면 모두 조회할 필요가 있지만 그게 아니라면 쓸데없는 호출이 생기는 것이다.
  • 그래서 지연로딩인 FetchType.LAZY 설정을 통해 실제 조회하여 가져오는 것이 아닌 프록시 객체인 빈 껍데기를 넣어 만들어준다.
    • 이것도 결국 모두 조회가 필요한 경우 지연로딩도 N + 1 문제가 발생할 수 있는데 뒤에서 Fetch Join을 통해 해결할 수 있다.

프록시

  • 프록시는 JPA에서 중요한 개념인데 가짜 객체라고 할 수 있다.
  • 위에서 언급한 것처럼 Lazy설정을 하거나 getReference를 이용해 조회를 할 수 있는데 이 경우 실제 엔티티를 상속한 프록시 객체가 생성되는것이다.
    • 이미 영속성 컨텍스트에 해당 엔티티가 있는 경우에는 getReference를 통해 호출해도 프록시 객체가 아닌 엔티티로 가져온다.
    • JPA는 한 트랙잭션 안에서 같은 객체에 대해 동일성을 보장하므로 반대의 경우 이미 프록시 객체인 경우에는 엔티티를 호출하여도 프록시 객체로 초기화 된다.
  • 그리고 프록시 객체를 사용하는 시점에 실제 엔티티의 값이 초기화 된다.
  • 엔티티가 초기화 되어도 한 번 프록시 객체였던 것은 항상 프록시 객체를 통해 조회한다.
  • 엔티티를 초기화하기 위해 영속성 컨텍스트에 요청을 하게 되는데 영속성 컨텍스트에 없는 경우(준영속 상태나 컨텍스트가 종료된경우) 에러가 발생한다.

지연 로딩 LAZY

  • 이미 위에서 설명했지만 JPA에서 중요한 문제이기 때문에 다시 정리한다.
  • N + 1 문제를 해결하기 위해 우선 프록시 객체를 주입한 후 프록시 객체를 호출하는 시점에 엔티티를 초기화 한다. ( 이때 쿼리 날라감)
  • 이와 반대되는 개념이 즉시 로딩 EAGER이 있다.
    • 엔티티를 조회할 때 이와 관련된 엔티티도 모두 같이 한 번에 조회하는 것이다.
      • 모든 값을 join해서 가져온다.
      • 그럼 모든 값이 필요한 경우 LAZY로 하게 되면 여러번의 쿼리가 날라가게 되는데 이 경우에는 한 번의 쿼리로 해결가능 하다.
      • 하지만 join하는 테이블이 많아질 경우 예상치 못한 쿼리가 생길 수 있고 성능이 안 좋아지게 된다.
    • JPQL에서는 위에서 말한 N + 1 문제가 일어나게 된다.
  • 이러한 즉시 로딩의 문제점들로 인해 지연 로딩을 설정해서 사용해 주는 것이 좋다.
    • ManyToOne과 OneToOne은 기본이 EAGER로 설정되어 있기 때문에 두 경우에 대해 LAZY 설정해 주어야 한다.

영속성 전이

  • 엔티티에 안에 있는 객체(엔티티)에 대해 영속성 컨텍스트를 같이 관리해준다.
    • ex ) A엔티티 안에 포함된 B엔티티를 초기화해주고 A엔티티를 저장해주면 B엔티티도 같이 영속성 컨텍스트에 저장된다.
  • cascade 타입을 지정해 주는데 CascadeType 은 ALL, PERSIST, REMOVE 등등 있다.
  • 두 엔티티의 라이프 사이클이 같으면서 포함된 엔티티가 포함하는 엔티티에만 종속적인 경우 사용한다.

고아 객체

  • 부모 엔티티와 연관관계가 끊어지면 자식 엔티티를 자동으로 삭제한다.
  • orphanRemoval 속성을 true하여 사용해준다.
  • 부모 객체를 삭제하면 마찬가지로 자식 엔티티가 모두 삭제된다.
  • 참조하는 곳이 하나일 경우 & 특정 엔티티에만 종속적인 경우 사용해야한다. 주의 필요

영속성 전이와 고아 객체 개념은 도메인 주도 설계 Aggregate Root 개념을 사용할 때 유용하다.

 

- 인프런 김영한님의 JPA 기본편을 듣고 정리한 내용입니다 -

'스프링 > JPA' 카테고리의 다른 글

JPA 기본 정리 #4  (0) 2023.09.03
JPA 기본 정리 #2  (0) 2023.09.03
JPA 기본 정리 #1  (0) 2023.08.31
Comments