Back-end/JPA
자바 ORM 표준 JPA 프록시
이안_ian
2023. 5. 31. 12:55
반응형
프록시 기초
em.find() : 데이터베이스를 통해서 실제 엔티티 객체 조회
em.getReference() : 데이터베이스 조회를 미루는 가짜(프록시)엔티티 객체 조회
em.getReference()로 가져온 member의 getClass를 해볼 경우 Member가 아닌 Member@DFnadjwProxy 식으로 매핑이 되어 있다. 값 또한 null로 아직 아무것도 없는 상태다.
이럴때 값에 접근하려고 getName() 해면 그때 영속성 컨텍스트에 초기화를 요청하여 DB에서 객체를 생성한다.
특이한 점은 바로 객체를 리턴하지 않고 연결만 시켜줘서 값을 읽어 온다는 점이다.
즉, getName()을 하더라도 class는 Member가 아니라는 점이다.
프록시의 특징
- 프록시 객체는 처음 사용할 때 한 번만 초기화
- 프록시 객체를 초기화 할 때, 프록시 객체가 실제 엔티티로 바뀌는 것은 아님, 초기화되면 프록시 객체를 통해서 실제 엔티티에 접근 가능
- 프록시 객체는 원본 엔티티를 상속받음, 따라서 타입 체크시 주의해야함(==비교 실패, 대신 instance of 사용)
- 영속성 컨텍스트에 찾는 엔티티가 이미 있으면 em.getReference()를 호출해도 실제 엔티티 반환, 반대도 마찬가지
- 영속성 컨텍스트의 도움을 받을 수 없는 준영속 상태일 때, 프록시를 초기화하면 문제 발생
Member m1 = em.find(Member.class, 1L);
Member m2 = em.getReference(Member.class, 2L);
m1.getClass() == m2.getClass() //false
Member m1 = em.find(Member.class, 1L);
Member m2 = em.getReference(Member.class, 1L); //이미 find한 객체를 호출
m1.getClass() == m2.getClass() //true 둘다 Member
Member m1 = em.getReference(Member.class, 1L);
Member m2 = em.find(Member.class, 1L);
m1.getClass() == m2.getClass() //true 둘다 Proxy
그러나 실제 업무에서는 em.getReference()를 직접 사용하진 않고 지연 로딩에 프록시 매커니즘이 사용된다.
지연로딩
@Entity
public class Member {
@Id
@GeneratedValue
private Long id;
private String name;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = 'team_id')
private Team team;
}
객체에서 연관관계를 설정할 때 LAZY를 쓰지않는다면
Member를 find 할때 자동으로 Team이 join되어 쿼리가 실행된다.
많은 연관관계가 있다면 이들 모두 join이 걸리게 될 것이고, 다 사용하지 않는다면 성능을 떨어뜨리는 요소가 될 뿐이다.
그래서 해당 값을 사용할 때 select 하는 전략이 LAZY 방식인 거다.
반응형