백엔드 개발자
JPA 기본 정리 #3 본문
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