본문 바로가기

Dev/JPA

프록시와 연관관계 관리

프록시와 연관관계 관리(난이도 상)

 

멤버와 팀과의 관계에서 연관관계가 맺어져 있지만

어떤 경우에는 멤버의 정보와 팀정보를 다 가져오고 다른 경우에는 팀정보가 아닌 멤버의 정보만 가져오고 싶을때

어떻게 해야할까???

// 멤버와 팀을 모두 가져오는 경우
public void printUserAndTeam(String memberId) {

	Member member = em.find(Member.class, memberId);

	Team team = member.getTeam();

	System.out.println("회원 이름: " + member.getUsername());
	System.out.println("소속팀: " + team.getName()); 
}
// 멤버만 가져오는 경우
public void printUser(String memberId) {

	Member member = em.find(Member.class, memberId);

	Team team = member.getTeam();

	System.out.println("회원 이름: " + member.getUsername());
}

JPA입장에서는 다 땡겨온다고 가정했을 때 멤버만 가져올때도 다 땡겨오니까 낭비가 되버린다!!!

 


프록시 기초

em.find() vs em.getReference()

em.find() : 데이터베이스를 통해서 실제 엔티티 조회 / 진짜 객체를 줌

 em.find는 이미 persist를 통해 디비에 들어가있는 데이터들을 select해서 가져올 수 있다.

 

em.getReference() : 데이터베이스 조회를  미루는 가짜(프록시) 엔티티 객체 조회 / 가짜 객체를 줌

getReference는 호출하는 시점에는 데이터베이스에 쿼리를 던져주지 않는다.

이 객체가 실제로 사용(실행)되는 시점에서야 select해서 가져온다.

 

프록시 기초

 

프록시 특징

실제 클래스를 상속받아서 만들어짐 그렇기때문에 실제 클래스와 겉 모양이 같다.

사용하는 입장에서는 진짜인지 가짜인지 구분할 필요없이 사용하면 된다. (이론상)

 

  • 프록시라는 텅텅빈 가짜 테이블에는 getId(), getName()를 들고 있고 실제 엔티티를 상속하는 형태이다.
  • 프록시 안에는 텅텅빈 상태인데 이 안에는 실제 객체의 참조 target을 들고 있다.
  • 프록시 객체를 호출하면 프록시 객체는 참조하는 객체를 조회한다.

프록시 특징

프록시 객체는 처음 사용할 때 딱 한번만 초기화

프록시 객체를 초기화 할 때, 프록시 객체가 실제 엔티티로 바뀌는게 아님 초기화 되면 프록시 객체를 통해서 실제 엔티티에 접근이 가능하다 라는 뜻

프록시 객체는 원본 엔티티를 상속받음, 따라서 타입 체크시에 주의해야함

( == 연산자로 타입을 비교하면 false / instance of 사용해서 타입비교는 정확하게 해줘야함) 타입 비교는 정확성을 요구하기 때문에

영속성 컨텍스트에 찾는 엔티티가 이미 있으면 em.getReference()를 호출해도 실제 엔티티를 반환

 

프록시 객체의 초기화

Member member = em.getReference(Member.class, “id1”); 
// 이과정까지는 쿼리상으로 아무런 동작이 없다.
member.getName();
// 실제로 getName()해서 뭔가 액션을 취해줬을때 프록시가 작동한다.


영속성 컨텍스트의 도움을 받을 수 없는 준영속 상태일때, 프록시를 초기화하는 문제 발생

(하이버네이트에서는 org.hibernate.LazyInitializationException 발생시킴)

 → 프록시는 영속성 컨텍스트의 도움을 받아 의존해서 작동하는 것이기 때문에 에러 발생

준영속 상태일 때 오류

프록시 확인하는 메서드

프록시 인스턴스의 초기화 여부 확인

PersistenceUnitUtil.isLoaded(Object entity)

 

프록시 클래스 확인 방법

entity.getClass().getName() 출력 (..javasist.. or HibernateProxy…)

 

프록시 강제 초기화

org.hibernate.Hibernate.initialize(entity); 이거는 하이버네이트가 제공하는 것

 

참고 : JPA 표준은 강제 초기화 없음

강제 호출 : member.getName()

 

 

 

'Dev > JPA' 카테고리의 다른 글

RS) SQL 중심적인 개발의 문제점  (0) 2022.02.01
JPA의 사용  (0) 2021.04.09
JPA 상속관계 매핑  (0) 2020.07.30
다양한 연관관계 매핑  (0) 2020.07.28
연관관계 매핑 기초  (0) 2020.07.15