JPA

프록시와 연관관계 관리

유휴 2022. 12. 4. 17:26

강의참고 - 자바 ORM 표준 JPA 프로그래밍 - 기본편

 

자바 ORM 표준 JPA 프로그래밍 - 기본편 - 인프런 | 강의

JPA를 처음 접하거나, 실무에서 JPA를 사용하지만 기본 이론이 부족하신 분들이 JPA의 기본 이론을 탄탄하게 학습해서 초보자도 실무에서 자신있게 JPA를 사용할 수 있습니다., - 강의 소개 | 인프런

www.inflearn.com

 

 목표

- 프록시에 대해서 이해한다.

- 즉시로딩과 지연로딩에 대해서 알아본다.

 

프록시 객체란?

- 특정 객체를 감싸는 wrapper 클래스 이다.

- 실제 클래스를 상속 받아서 만들어지며, 실제 클래스와 겉 모양이 동일하다.

- 실제 객체의 요청을 대신받아서 메소드 호출 이전, 이후에 대한 로직을 추가적으로 수행 할 수 있는 객체이다.

 

프록시 엔티티 객체를 가져오는 방법

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

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

 

프록시 객체의 초기화

Member member = em.getReference(Member.class, "id1");
member.getName(); // 해당 시점에 쿼리실행

 

프록시 엔티티 객체의 특징

- 프록시 객체는 원본 객체를 상속 받으며, 타입체크 시에 주의해야한다. == 대신 Instance of 사용

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

- 영속성 컨텍스트의 도움을 받을 수 없는 준영속 상태일때, 프록시를 초기화하면 org.hibernate.LazyInitailzationException 예외 발생

 

프록시 엔티티 객체 확인방법

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

   PersistenceUnitUtil.isLoaded(Object entity)

- 프록시 클래스 여부 확인 방법

   entity.getClass().getName()

- 프록시 강제 초기화

   org.hibernate.Hibernate.initialize(entity);

 

 

즉시로딩과 지연로딩

- 즉시로딩 : 엔티티 조회 시점에 연관관계가 설정되어있는 엔티티를 조인하여 한번에 조회하는 기능이다.

- 지연로딩 : 엔티티 조회 시점에 연관관계가 설정되어있는 엔티티는 제외하고 해당 엔티티만 조회해오는 기능이다.

                   * 엔티티 조회시점에 실제 엔티티가 아닌, 프록시 엔티티 객체를 가져온다.

                   * 연관관계가 있는 필드조회 시점에 해당 엔티티의 조회쿼리가 실행된다.

 

즉시로딩 구현코드

@Entity
public class Member {
	
    @Id
    @generatedValue
    private Long id
    
    @Column(name="USERNAME")
    prviate String name;
    
	@ManyToOne(fetch=FetchType.EAGER) // 지연로딩 설정
	@JoinColumn(name="TEAM_ID")
	private Team team;
}

public class Test {
	
    public void executeEagerTest(){
    	Member member = em.find(Member.class, 1L); // Member와 Team을 조인하여 한번에 가져오는 SQL실행
        Team team = member.getTeam(); // 실제 Team 엔티티 객체 반환
        team.getName();
    }
}

 

지연로딩 구현코드

@Entity
public class Member {
	
    @Id
    @generatedValue
    private Long id
    
    @Column(name="USERNAME")
    prviate String name;
    
	@ManyToOne(fetch=FetchType.LAZY) // 지연로딩 설정
	@JoinColumn(name="TEAM_ID")
	private Team team;
}

public class Test {
	
    public void executeLazyTest(){
    	Member member = em.find(Member.class, 1L);
        Team team = member.getTeam(); // 프록시 엔티티 객체를 가져온다.
        team.getName(); // 실제 team을 사용하는 시점에 쿼리가 실행되며, 프록시 엔티티 객체 초기화
    }
}

 

프록시와 즉시로딩 주의

- 즉시 로딩을 적용하면 예상하지 못한 SQL이 발생하므로 가급적 지연로딩을 사용한다.

- @ManyToOne, @OneToOne은 기본이 즉시로딩이므로 LAZY로 설정한다.

- @OneToMany, @ManyToMany는 기본이 지연 로딩이다.