JPA - Proxy

2023. 12. 10. 04:21·Spring/JPA
728x90
반응형
SMALL

 

프록시 객체란?
  • 해당 엔티티와 연관된 다른 엔티티를 한 번에 조회하지 않고 실제로 필요할 때 프록시 객체를 초기화시켜 사용한다.
  • 프록시 객체를 사용하면 자원 낭비를 막을 수 있다.
  • 지연 로딩을 이해하기 위해 필요한 기초 개념
  • em.getReference()라는 메서드로 프록시 객체인지 확인 가능
  • em.find()는 실제 엔티티 객체를 조회하는 메서드

 

프록시의 특징

  • 실제 클래스를 상속받아서 만들어진다.
    • 하이버네이트가 내부적으로 상속받음
  • 실제 클래스와 동일한 타입처럼 보인다.
  • 사용하는 입장에서는 진짜 객체인지 프록시 객체인지 구분하지 않고 사용한다.
  • 프록시 객체는 실제 객체의 참조대상을 보관한다.
  • 프록시 객체를 호출하면 프록시 객체는 실제 객체의 메소드를 호출한다.
  •  

 

프록시 객체의 초기화

  1. Member객체를 em.getReference(Member.class,member.getId())로 호출한다.
  1. MemberProxy객체에 처음에는 target값이 존재하지 않는다. 아직 실제 Member를 불러오지 않았기 때문
  1. 영속성 컨텍스트에 초기화 요청을 한다
  1. 컨텍스트가 DB에서 실제 Member객체가 존재하면 불러와 Member객체를 생성해준다.
  1. 프록시 객체가 갖고 있는 target의 getName을 target에서 가지고온다
  1. 프록시 객체에 target이 참조되면, 더 이상 프록시 객체의 초기화 동작은 없어도 된다.

 

 

프록시 개념 정리

  • 프록시 객체는 처음 사용할 떄 한 번 초기화 된다
  • 프록시 객체를 초기화 할 때, 프록시 객체가 실제로 엔티티로 바뀌는 것은 아니다
  • 정확히 말하면 target에 값이 채워지는 것
  • 프록시 객체와 상속받고 있는 객체는 타입이 다르다. 타입을 체크할 떄 주의해야 한다.
  • 타입 체크를 위해 instanceOf를 사용해야 한다.
  • 영속성 컨텍스트에 이미 찾는 엔티티가 있다면, getReference()메서드로 호출해도 실제 엔티티를 반환한다. 굳이 존재하는 객체를 다시 Proxy객체로 래핑하는게 성능상 이점이 없기 때문
  • JPA는 하나의 영속성 커텍스트에 조회하는 같은 엔티티의 동일성을 보장한다.

 

 

현업에서 겪는 문제

  • 준영속 상태일때, 초기화 문제에서 발생
  • 트랜잭션 범위 밖의 프록시 객체를 조회하려 할 떄 발생한다.
  • 하이버네이트는 LazyInitiailizationException예외를 발생시킨다.
  • 이를 해겨하기 위해 open-in-view설정을 true로 가져간다.
  • 영속성 컨텍스트를 뷰 렌더링하는 시점까지 유지시키는 방법
  • em.detach(준영속상태로 만드는 것,em.close(),em.clear 모두 같은 예외 발생
  • 프록시 객체를 초기화 할 수 없다. 더 이상 영속성 컨텍스트의 도움을 받지 못한다.예시 코드

  •  
  • @SpringBootTest @Transactional @Rollback(value = false) class ProxyTest { @Autowired EntityManager em; @Test public void checkProxy(){ Member member = new Member(); member.setUsername("memberA"); em.persist(member); em.flush(); em.clear(); Member findMember = em.getReference(Member.class, member.getId()); //준영속상태로 만들기 em.detach(findMember); System.out.println("findMember = " + findMember.getUsername()); } }

결과

  • LazyInitializationException 예외가 발생
  • could not initialize proxy 라고 뜬다. 영속성 컨텍스트에서 관리하는 객체가 아니기 때문
org.hibernate.LazyInitializationException: could not initialize proxy [study.jpa.queryDSL.domain.Member#1] - no Session

	at org.hibernate.proxy.AbstractLazyInitializer.initialize(AbstractLazyInitializer.java:176)
	at org.hibernate.proxy.AbstractLazyInitializer.getImplementation(AbstractLazyInitializer.java:322)
	at org.hibernate.proxy.pojo.bytebuddy.ByteBuddyInterceptor.intercept(ByteBuddyInterceptor.java:45)
	at org.hibernate.proxy.ProxyConfiguration$InterceptorDispatcher.intercept(ProxyConfiguration.java:95)
	at study.jpa.queryDSL.domain.Member$HibernateProxy$5vcprY27.getUsername(Unknown Source)
	at study.jpa.queryDSL.domain.ProxyTest.checkProxy(ProxyTest.java:34)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.base/java.lang.reflect.Method.invoke(Method.java:566)

프록시 초기화 상태 확인

  • EntityManagerFactory를 호출하여 getPersistenceUnitUtil().isLoaded(Entity)를 사용하면 초기화된 상태인지 확인할 수 있다.
@Autowired
    EntityManager em;
    @PersistenceUnit
    EntityManagerFactory emf;
    @Test
    public void checkProxy(){
        Member member = new Member();
        member.setUsername("memberA");
        em.persist(member);

        em.flush();
        em.clear();

        Member findMember = em.getReference(Member.class, member.getId());

        //준영속상태로 만들기
        em.detach(findMember);

        //proxy의 초기화 상태를 확인할 수 있다.
        boolean loaded = emf.getPersistenceUnitUtil().isLoaded(findMember);
        System.out.println("loaded = " + loaded);

    }

결과

  • 초기화되지 않은 객체임을 확인 가능
/* insert study.jpa.queryDSL.domain.Member */ insert into member (created_by, created_date, last_modifed_by, last_modifed_date, age, team_id, username, member_id) values (?, ?, ?, ?, ?, ?, ?, ?)
/* insert study.jpa.queryDSL.domain.Member */ insert into member (created_by, created_date, last_modifed_by, last_modifed_date, age, team_id, username, member_id) values (NULL, NULL, NULL, NULL, 0, NULL, 'memberA', 1);
loaded = false

 

 

728x90
반응형
SMALL

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

@Where Deprecated되고 새로 쓰이는 @SQLRestriction  (1) 2024.11.20
JPA - DB 연결 예외 : 'url' attribute is not specified and no embedded datasource could be configured.  (0) 2024.06.14
JPA - 지연로딩과 즉시로딩  (1) 2023.12.10
JPA - MappedSuperClass  (0) 2023.12.10
JPA - 상속관계매핑  (0) 2023.12.09
'Spring/JPA' 카테고리의 다른 글
  • JPA - DB 연결 예외 : 'url' attribute is not specified and no embedded datasource could be configured.
  • JPA - 지연로딩과 즉시로딩
  • JPA - MappedSuperClass
  • JPA - 상속관계매핑
공부하고 기억하는 공간
공부하고 기억하는 공간
IT 비전공자로 시작하여 훌륭한 개발자가 되기 위해 공부하고 있는 공간입니다. 틀린 내용이나 부족한 부분이 있으면 댓글로 알려주세요 바로 수정하겠습니다.
    250x250
  • 공부하고 기억하는 공간
    IT - railroad
    공부하고 기억하는 공간
  • 전체
    오늘
    어제
    • 분류 전체보기 (314)
      • 면접 준비 (36)
        • OS (6)
        • Spring Security (0)
        • Java (2)
        • DB (9)
        • Network (3)
      • ElasticSearch (2)
      • Kafka (4)
      • Spring (22)
        • Spring Cloud (7)
        • Security6 (5)
        • JPA (12)
        • 프로젝트 리팩토링 회고록 (4)
        • Logging (8)
        • Batch (2)
      • Redis (17)
        • Redis 개념 (8)
        • Redis 채팅 (5)
        • Redis 읽기쓰기 전략 (1)
      • AWS (11)
      • 리눅스 (29)
        • 리눅스 마스터 2급 (5)
        • 네트워크(기초) (7)
        • 리눅스의 이해 (6)
        • 리눅스의 설치 (2)
        • 리눅스 운영 및 관리 (6)
      • JAVA-기초 (16)
        • JAVA기본 (11)
        • Design Pattern (5)
      • JSP (27)
        • JSP 기본 개념 (10)
        • JSP (1)
      • SQL (1)
      • TIL (36)
      • 문제 풀이 (2)
        • Programmers (9)
        • 백준 문제풀이 (28)
      • JavaScript (10)
      • HTML (17)
      • Ngrinder (1)
        • Ngrinder 문서 정리 (1)
  • 블로그 메뉴

    • 링크

    • 공지사항

    • 인기 글

    • 태그

      JS
      Til
      Springframework
      jsp request
      JavaScript
      리눅스마스터2급정리
      redis
      자바 면접
      자바 알고리즘
      리눅스마스터2급
      redis 채팅
      레디스
      java
      자바스크립트
      자바 면접질문
      리눅스
      CSS
      Spring
      JSP
      스프링프레임워크
      HTML
      jsp기초
      자바 반복문
      백준
      프로그래머스
      자바기초
      springsecurity
      Spring Data Redis
      spring redis
      자바
    • 최근 댓글

    • 최근 글

    • hELLO· Designed By정상우.v4.10.3
    공부하고 기억하는 공간
    JPA - Proxy
    상단으로

    티스토리툴바