본문 바로가기

JPA

프록시

만약, 멤버 클래스와 팀 클래스가 연관관계로 매핑되어 있다고 가정하자.

이때, 조회는 아래와 같이 3가지의 경우의 수가 있다.

  1. 멤버만 조회
  2. 팀만 조회
  3. 멤버와 팀 모두 조회

하지만, 팀과 멤버는 연관관계 매핑이 되어있어, 우리는 멤버 혹은 팀 하나만 조회하고 싶은데, 항상 한번에 양 쪽을 모두  select 쿼리를 날려 가져온다. 

//1. member 생성 후, 저장
Team team = new Team();
Member member = new Mmeber();

member.setName("son");
member.setTeam(team); 

em.persist(member);
em.flush();
em.clear();

//2. member만 조회
Member member = em.find(Member.class, 1L);

//3. 하지만, Team까지 같이 가져와버려, 팀도 조회가 된다...!
Team team = member.getTeam();

 

이러한 문제를 JPA는 지연로딩즉시로딩으로 해결한다.

 

지연로딩과 즉시로딩을 이해하기 위해서는 먼저, 프록시에 대해서 이해를 해야한다.

 

프록시에 대해

프록시 = 임시 참조 객체. 초기에는 빈 껍데기만 있는 객체이고, 실제 사용 시, 프록시 객체 안에 실제 DB의 값들이 채워진다. (type은 변하지 않음!)

JPA에서는 조회에 대해 2개의 함수가 있다.

1. em.find()
2. em.getRefenrence()
  1. em.find()
    1. DB에서 실제 엔티티 객체를 조회해 가져온다.
    2. 조회 시점에 바로 Select 쿼리가 날라감.
  2. em.getReference()
    • DB 조회를 미루는 가짜(프록시) 엔티티 객체를 조회해 가져온다.
    • 조회할 때 Select 쿼리가 안날라가고, 실제 데이터를 사용할 때, 쿼리가 날라감.
//이때, 조회(Select) 쿼리문이 바로 날라감.
//member는 실제 Entity 객체
Member member = em.find(Member.class, 1L);
//select 쿼리문 안날라감
//member는 가짜 프록시 객체
Member member = em.getReference(Member.class, 1L);

//이때, 쿼리문 날라감
//이렇게, 데이터 직접 사용으로 인해 조회가 필요할 때, 쿼리문이 날라간다.
//이때, member는 실제 Entity 객체가 된다.
System.out.println(member.getName);

 

  • JPA는 항상 프록시와 실제 객체의 "==" 비교를 True로 보장해준다.
mem1 = em.getReference(Member.class, 1L); //프록시 객체 반환
mem2 = em.find(Member.class, 1L); // mem1과의 "=="비교를 보장해주기 위해 프록시 객체 반환

sout(mem1 == mem2) // True 반환...

 

  • 준영속 상태에서 프록시 초기화 ➡️ Error
Member member = em.getReference(Member.class, 1L);
em.detach(member);
//or em.close();

//에러 발생, 영속성 컨텍스트 내 member가 준영속 상태 or 영속성 컨텍스트가 닫혀 프록시 객체를 초기화할 수 없다.
member.getName();

'JPA' 카테고리의 다른 글

조건식 (case, coalesce, nullif)  (0) 2023.05.29
즉시로딩(EAGER Loading)과 지연로딩(LAZY LOADING)  (0) 2023.05.23
JPA - 연관관계 주인(feat. mappedBy)  (0) 2023.05.19
영속성 컨텍스트!  (2) 2023.05.11
자바의 트랜잭션  (0) 2023.05.09