일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | ||||||
2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 | 17 | 18 | 19 | 20 | 21 | 22 |
23 | 24 | 25 | 26 | 27 | 28 |
- BOJ
- 낙관적락
- execute
- 유니크제약조건
- eager
- 연관관계
- FetchType
- 일대다
- 지연로딩
- shared lock
- 비관적락
- JPQL
- 백트래킹
- 다대다
- SQL프로그래밍
- 힙
- 스토어드 프로시저
- fetch
- dfs
- 이진탐색
- 즉시로딩
- exclusive lock
- querydsl
- PS
- 데코레이터
- CHECK OPTION
- 연결리스트
- 스프링 폼
- 다대일
- 동적sql
- Today
- Total
흰 스타렉스에서 내가 내리지
[JPA] 프록시, 즉시로딩, 지연로딩 본문
엔티티를 조회할 때 사용하지 않는 연관된 엔티티까지 데이터베이스에서 함께 조회해 두는 것은 효율적이지 않다.
JPA는 이런 문제를 해결하려고 엔티티가 실제 사용될 때까지 데이터베이스 조회를 지연하는 방법을 제공하는데 이것을 지연로딩이라고 한다.
team.getName() 처럼 팀 엔티티 값을 실제 사용하는 시점에 데이터베이스에서 팀 엔티티에 필요한 데이터를 조회하는 것이다.
그런데 지연로딩 기능을 사용하려면 실제 엔티티 객체 대신에 데이터베이스 조회를 지연할 수 있는 가짜 객체가 필요한데 이것을 프록시 객체라고 한다.
Member member = em.find(Member.class, "member1");
이렇게 엔티티를 직접 조회하면 조회한 엔티티를 실제 사용하든 사용하지 않든 데이터베이스를 조회하게 된다.
엔티티를 실제 사용하는 시점까지 데이터베이스 조회를 미루고 싶으면 EntityManager.getReference() 메소드를 사용하면 된다.
Member member = em.getReference(Member.class, "member1");
이 메소드를 호출할 때 JPA는 데이터베이스를 조회하지 않고 실제 엔티티 객체도 생성하지 않는다.
대신에 데이터베이스 접근을 위임한 프록시 객체를 반환한다.
프록시
프록시 클래스는 실제 클래스를 상속 받아서 만들어지므로 실제 클래스와 겉 모양이 같다.
프록시 객체는 실제 객체에 대한 참조(target)를 보관한다.
그리고 프록시 객체의 메소드를 호출하면 프록시 객체는 실제 객체의 메소드를 호출한다.
// 프록시 클래스 예상 코드
public class MemberProxy extends Member{
Member target = null; // 실제 엔티티 참조
public String getName(){
if(target == null){
// 2. 초기화 요청
// 3. DB 조회
// 4. 실제 엔티티 생성 및 참조 보관
this.target = ...;
}
// 5. target.getName();
return target.getName();
}
}
영속성 컨텍스트에 찾는 엔티티가 이미 있으면 데이터베이스를 조회할 필요가 없으므로 em.getReference() 를 호출해도 프록시가 아닌 실제 엔티티를 반환한다.
프록시 객체는 식별자 값을 보관한다.
Team team = em.getReference(Team.class, "team1"); //식별자 보관
team.getId(); //초기화되지 않음
@Access(AccessType.PROPERTY) 로 설정한 경우에는 team.getId() 를 호출해도 프록시를 초기화하지 않는다.
@Access(AccessType.FIELD) 로 설정한 경우에는 team.getId() 를 호출해도 프록시 객체를 초기화한다.
프록시 객체는 주로 연관된 엔티티를 지연 로딩할 때 사용한다.
즉시로딩과 지연로딩
즉시로딩 : 엔티티를 조회할 때 연관된 엔티티도 함께 조회한다.
@ManyToOne(fetch = FetchType.EAGER)
지연로딩 : 연관된 엔티티를 실제 사용할 때 조회한다.
@ManyToOne(fetch = FetchType.LAZY)
fetch 속성의 기본 설정값은 다음과 같다.
- @ManyToOne, @OneToOne : 즉시로딩 (FetchType.EAGER)
- @OneToMany, @ManyToMany : 지연로딩 (FetchType.LAZY)
JPA의 기본 fetch 전략은 연관된 엔티티가 하나면 즉시 로딩을, 컬렉션이면 지연 로딩을 사용한다.
추천하는 방법은 모든 연관관계에 지연 로딩을 사용하는 것이다. 그리고 애플리케이션 개발이 어느 정도 완료단계에 왔을 때 실제 사용하는 상황을 보고 꼭 필요한 곳에만 즉시 로딩을 사용하도록 최적화하면 된다.
'Spring' 카테고리의 다른 글
[JPA] 값 타입1 - 복합, 연관관계, 재정의, 복사, 비교 (0) | 2023.02.19 |
---|---|
[JPA] 영속성 전이 : CASCADE, 고아 객체 (0) | 2023.02.19 |
[JPA] 조인 테이블(연결 테이블) (0) | 2023.02.16 |
[JPA]일대일 식별 관계 (0) | 2023.02.15 |
[JPA] 복합 키 : 식별 관계 매핑 (0) | 2023.02.11 |