프록시 기초
- em.find() 와 em.getReference()
- em.find 의 경우 데이터베이스를 통해서 실제 엔티티 객체 조회
- em.getReference 의 경우 데이터베이스 조회를 미루는 가짜 프록시 엔티티 객체 조회
- 사용하는 시점에 실제 쿼리를 요청함
프록시 특징 (1)
- 실제 클래스를 상속 받아서 만들어짐
- 실제 클래스와 겉 모양이 같다.
- 사용하는 입장에서는 이론상 진짜 객체인지 프록시 객체인지 구분하지 않고 사용하면 된다.
- 프록시 객체는 실제 객체의 참조(Target) 를 보관
- 프록시 객체를 호출하면 프록시 객체는 실제 객체의 메소드 호출
프록시 객체의 초기화
- 실제 엔티티 정보 조회 요청
- 초기화 요청 → 영속성 컨텍스트
- 영속성 컨텍스트를 통하여 DB 조회
- 실제 Entity 생성
- 해당 Entity (Target) 를 통하여 요청한 정보 획득
프록시 특징 (2)
- 프록시 객체는 처음 사용할 때 한 번만 초기화
- 프록시 객체 초기화 시 프록시 객체가 해당 엔티티에 접근이 가능한 것이지 실제 엔티티로 바뀌는 것은 아니다
- 프록시 객체는 원본 엔티티를 상속 받음, 따라서 타입 체크시 주의 (instance of)
- 영속성 컨텍스트에 찾는 엔티티가 이미 있다면, em.getReference 를 호출하여도 실제 엔티티를 반환
- 영속성 컨텍스트의 도움을 받을 수 없는 준영속 상태일 때, 프록시를 초기화 하면 문제 발생 - LazyInitializationException 예외
한 트랜잭션 안에서 == 비교 값을 true 로 맞추기 위해 필요한 객체를 반환한다.
프록시 확인
- 프록시 인스턴스의 초기화 여부 확인 - PersistenceUnitUtil.isLoaded(Object entity)
- 프록시 클래스 확인 방법 - entity.getClass().getName()
- 프록시 강제 초기화
참고로 JPA 표준은 강제 초기화 없음 따라서, 강제 호출 (실제 정보를 요청)해야 초기화가 된다. - member.getName()
지연 로딩과 프록시
지연 로딩의 경우 엔티티 조회 시 해당 객체를 프록시로 조회한다.
그리고 실제 연관관계 엔티티를 사용하는 시점에 초기화 한다. (DB 조회)
반대로 즉시 로딩의 경우 연관관계 엔티티를 모두 조회해오는 방식
프록시와 즉시 로딩 주의
- 가급적 지연 로딩만 사용하자
- 즉시 로딩을 적용하면 예상하지 못한 SQL 이 발생
- 즉시 로딩은 JPQL 에서 N + 1 문제를 일으킨다.
- @ManyToOne, @OneToOne 은 기본이 즉시 로딩, 지연 로딩으로 바꿔 쓰자
- 반대로 XtoMany 관계의 경우 기본이 지연 로딩
실무에서 지연 로딩 활용
- 모든 연관관계에 지연 로딩을 사용해라
- 실무에서 즉시 로딩을 사용하지 마라
- JPQL fetch 조인이나, 엔티티 그래프 기능을 사용해라
※주의 - 즉시 로딩의 경우 정말 상상하지 못한 쿼리가 요청된다.
참조
- 해당 게시글은 김영한님의 "자바 ORM 표준 JPA 프로그래밍 - 기본편" 을 바탕으로 작성되었습니다.
'JPA' 카테고리의 다른 글
쿼리 메소드 기능 (0) | 2021.01.26 |
---|---|
객체지향 쿼리 언어 (0) | 2021.01.25 |
값 타입 (0) | 2021.01.19 |
상속 관계 매핑 (0) | 2021.01.14 |
다양한 연관관계 매핑 (0) | 2021.01.12 |
댓글