JPA 프록시 지연로딩 즉시로딩
Proxy / Lazy Loading / Eager Loading
지연로딩 (Lazy Loading)
JPA 지연로딩은 프록시 객체의 메소드를 사용하는 시점에 데이터베이스에 쿼리문을 수행하여
엔티티를 조회하는 방식으로 동작한다.
지연로딩을 사용함으로써 연관관계이지만, 사용하지 않는 객체를 조회하는 쿼리문을 실행하지 않도록 하여
성능을 향상 시킬 수 있다.
public class User {
@GeneratedValue
@Id
@Column(unique = true, nullable = false)
private Integer id;
private String name;
@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY, mappedBy = "user")
private List<Card> cards = new ArrayList<>();
}
public class Card {
@GeneratedValue
@Id
@Column(unique = true, nullable = false)
private Integer id;
private Integer cnt;
@ManyToOne
private User user;
}
User <-> Card
OneToMany 관계
1. User 엔티티만 사용하는 경우
: User 엔티티를 조회하는 쿼리만 실행
2. User와 연관된 Card 엔티티도 사용하는 경우
: User, Card 엔티티 조회 쿼리 실행
1번 케이스에서 User의 멤버 변수 Card는 프록시 객체로 되어있을 것이다.
: JPA가 제공하는 PersistanceUnitUtil 을 통해 프록시 객체 초기화 여부를 확인할 수 있다.
프록시 객체 구조
: Card 엔티티를 상속받은 프록시 객체. getId() , getCnt() 메소드를 가짐.
또한 엔티티를 조회할 수 있는 식별자를 가진다 (여기서는 id).
프록시 객체의 동작
: 위의 2번 케이스에서 Card 엔티티의 toString()이 호출되었고, CardProxy는 그 시점에 DB를 조회하여 Card 엔티티를 초기화한다.
주의
* 프록시에서 엔티티 조회 시 영속성 컨텍스트가 사용되기 때문에 영속성 컨텍스트 범위 밖에서는 동작할 수 없다.
LazyInitializationException 발생.
* 이미 영속성 컨텍스트에 엔티티가 존재한다면 프록시 객체가 아닌 실제 엔티티로 초기화 된다.
즉시로딩 (Eager Loading)
지연로딩을 사용할 경우 연관관계가 있는 엔티티가 필요한 경우라면, Select 쿼리를 여러번 수행해서 엔티티를 조회하게 된다.
따라서 성능에 문제가 생길 수 있다.
만약 대부분의 경우에 연관관계에 있는 엔티티의 정보까지 사용이 된다면 즉시로딩을 사용할 수 있다.
즉시로딩을 사용할 경우 join을 사용하여 한번의 쿼리수행으로 연관관계에 있는 엔티티까지 조회되기 때문에
성능이 향상된다.
public class User {
...
@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER, mappedBy = "user")
private List<Card> cards = new ArrayList<>();
}
: User 엔티티 조회 시점에 join문으로 Card 엔티티 까지 조회한다.
JPA에서는 기본적으로 outer join을 사용하여 연관관계에 있는 엔티티를 조회한다.
(Inner를 사용하게 되면 Card가 없는 User 엔티티는 조회되지 않을 것이다)
하지만 무조건 Card가 있다고 가정하는 경우에는, inner join을 사용함으로써 성능을 좀 더 향상 시킬 수 있다.
(nullable=false , optional = false 옵션을 통해 JPA에 이 사실을 알려주어야 함)
또한 연관간계에 있는 엔티티의 수가 많을 경우, 메모리에 적재되는 엔티티의 수가 일정량 이상일 때
GC가 동작하여 오히려 성능이 더 느려질 수도 있다.
지연로딩, 즉시로딩 선택에는 신중을 기해야하고 책에 나온것처럼
지연로딩으로 먼저 설정하되 서비스 운영중에 필요한 부분을 즉시로딩으로 바꾸는 방식을 선택하는 방향이 좋아보인다.
※ 자바 ORM 표준 JPA 프로그래밍 참고
'JPA' 카테고리의 다른 글
(Spring/JPA/Transaction) 쓰기 스큐, 팬텀. Write skew, Phantom (0) | 2020.07.03 |
---|---|
(JPA) 엔티티매니져 플러시(EntityManager flush)란? (0) | 2020.04.20 |
(Spring/JPA) Spring transaction logging / jpa entity manager logging (0) | 2020.03.11 |
(JPA) JPA 성능개선이란? 성능개선 적용기 (fetch join/BatchSize) (3) | 2020.03.09 |
(JPA) JPA 성능개선이란? 성능개선 목록 (N+1문제/read-only/Non-Transactional..) (0) | 2020.03.07 |
댓글