ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 프록시
    JPA 2023. 1. 4. 18:38

    데이터를 조회할때 상황에 따라서 여러 데이터를 가져오거나 혹은 그 값만 가져오는 경우가 있다.
    예를 들어서 Member의 ID만을 가져오는 로직이 있고, Member의 TeamID까지 모두 가져오는 비즈니스 로직이 있다고 하면 로직에따라서 비효율이 발생할 수 있다.
    이를 지연로딩을 통해서 해결할 수 있다.

    • em.find: 데이터베이스를 통해서 실제 엔티티 객체 조회(쿼리가 나감)
    • em.getReference(): 데이터베이스 조회를 미루는 가짜(프록시)엔티티 객체 조회

    DB에 쿼리가 안나갔는데 객체 조회가 된다.

    Member member = new Member();
    member.setUsername("hello");
    
    em.persist(member);
    
    em.flush();
    em.clear();
    
    Member findMember = em.getReference(Member.class, member.getId());

    SELECT쿼리가 나가지 않았는데도 조회가 된다.
    getReference가 호출하는 시점에는 DB에 쿼리를 하지 않는다.

    그러나, 이값이 실제로 사용되는 시점

    member.getId()는 위에서 대입한 값이므로 이미 알고 있고, getUserName()같은 다른사용시점 에 SELECT문이 나가게 된다.
    getClass를 해보면

    class hellojpa.Member$HibernateProxy$pqmZO2Pa
    

    가 나오게 되는데, 이는 프록시가만든 가짜 클래스이다.

    getReferece를 하게되면 진짜 개체가 아니라, proxy라고 하는 가자 entity를 주게된다.(target은 진짜객체를 가리킨다.)


    Proxy내부에는 아무것도 없고, target이 존재하는데 이는 진짜객체를 가리킨다.

    • 실제 클래스를 상속 받아서 만들어짐
    • 실제 클래스와 겉 모양이 같다.

    프록시객체는 실제 객체의 참조를 보관한다.
    물론 처음에는 target은 없다.

    getReference를 하면 Proxy객체를 가져온다.
    getName()을 호출할때 이때 타겟은 아무것도 없다. 이때 영속성컨텍스트에 요청을 하게되고, 컨텍스트는 DB를 조회해서 실제 Entity를 생성하고, tartget에 연결해준다.
    따라서 타겟의 진짜 getName을 통해서 반환이 된다.

    프록시의 특징

    • 프록시 객체는 처음 사용할 때 한 번만 초기화
    • 프록시 객체를 초기화 할 때, 프록시 객체가 실제 엔티티로 바뀌는 것은 아님. 초기화되면 프록시 객체를 통해서 실제 엔티티에 접근 가능

    헷갈리지 말자

    • 프록시 객체는 원본 엔티티를 상속받음, 따라서 타입 체크시 주의해야함 (== 비교 실패, 대신 instance of 사용)
    • 영속성 컨텍스트에 찾는 엔티티가 이미 있으면 em.getReference()를 호출해도 실제 엔티티 반환
    • 영속성 컨텍스트의 도움을 받을 수 없는 준영속 상태일 때, 프록시를 초기화하면문제 발생
    728x90

    'JPA' 카테고리의 다른 글

    CASECADE  (0) 2023.01.04
    지연로딩과 즉시로딩  (0) 2023.01.04
    상속관계  (0) 2023.01.04
    다양한 연관관계 매핑2  (0) 2023.01.03
    다양한 연관관계 매핑1  (0) 2023.01.03

    댓글

Designed by Tistory.