본문 바로가기
Spring/JPA

JPA 프록시

by YoonJong 2022. 9. 26.
728x90

지연로딩을 이해 하기 위해서는 프록시에 대해 이해해야 쉽게 다가갈 수 있다.

 

강의에서는 시작을 해당 질문으로 시작한다.

" Member 엔티티를 조회할 때 Team 도 함께 조회해야 할까 ? "

 

해당 질문에 대한 답은 정해져있지 않다.

실제로 비즈니스 로직이 Member 엔티티를 조회할 때 꼭 Team 을 필요로 해야할 수도 있기 때문이다.

하지만, 보통은 같이 사용하지 않는 것이 일반적이다.

 

 - 비즈니스 로직에 꼭 필요하지 않다면 Team을 같이 조회할 필요가 없다.

 - 쿼리 등 낭비가 발생한다.

 - 해당 낭비를 줄이기 위해, 지연로딩과 프록시로 해결한다.

 

JPA 에서는 em.find () 뿐만 아니라, em.getReference() 메서드도 제공하고 있다.

em.find는 DB 를 통해서 실제 엔티티 객체를 조회하는 메서드이고

em.getRefence는 가짜 프록시 엔티티 객체를 조회하는 메서드 이다.

 

 

Member 엔티티를 조회할때 team 이 같이 조회되는 예시를 보자

em.find() 사용

@Entity
public class Member {

    @Id
    @GeneratedValue
    @Column(name = "member_id")
    private Long id;

    @Column(name = "username")
    private String name;

    @ManyToOne
    @JoinColumn(name = "team_id")
    private Team team;

 

Member member = new Member();
member.setName("member1");

em.persist(member);
em.flush();
em.clear();

Member findMember = em.find(Member.class, member.getId());
tx.commit();

 

쿼리를 보면 team 까지 같이 select 된 것을 볼 수 있다.

Hibernate: 
    select
        member0_.member_id as member_i1_6_0_,
        member0_.city as city2_6_0_,
        member0_.street as street3_6_0_,
        member0_.zipcode as zipcode4_6_0_,
        member0_.username as username5_6_0_,
        member0_.team_id as team_id6_6_0_,
        team1_.team_id as team_id1_11_1_,
        team1_.insert_member as insert_m2_11_1_,
        team1_.createdDate as createdD3_11_1_,
        team1_.update_member as update_m4_11_1_,
        team1_.modifiedDate as modified5_11_1_,
        team1_.name as name6_11_1_ 
    from
        Member member0_ 
    left outer join
        Team team1_ 
            on member0_.team_id=team1_.team_id 
    where
        member0_.member_id=?

 


 

em.getReference( ) 메서드를 사용해서 Class형태를 보면 Proxy 형태로 나오는 것을 볼 수 있다.

현재 프록시 객체를 얻기는 했지만, 아무런 동작을 하지 않았기 때문에 select 쿼리를 수행하지 않는다.

Member member = new Member();
member.setName("proxy");

em.persist(member);

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

Member findMember = em.getReference(Member.class, member.getId());
System.out.println("findMember.getClass() = " + findMember.getClass());

tx.commit();
Hibernate: 
    /* insert hellojpa.Member
        */ insert 
        into
            Member
            (city, street, zipcode, username, team_id, member_id) 
        values
            (?, ?, ?, ?, ?, ?)
findMember.getClass() = class hellojpa.Member$HibernateProxy$oN6J2xMt

 

프록시의 특징

 - 실제 클래스를 상속받아서 만들어진다.

 - 실제 클래스와 겉 모양이 같다.

 

 

프록시 객체의 초기화는 프록시 객체의 메서드를 호출할때 초기화가 된다. ( 처음 사용할 때 )

프록시 객체를 초기화하면 실제 엔티티로 바뀌는것아 아니다.

프록시 객체는 원본 엔티티를 상속받으므로, instanceof 를 통해 비교해야 한다 ( == 비교불가 )

getName 메서드를 통해 초기화 요청을 한다. ( 프록시객체에는 target 값이 존재하지 않는다 )

영속성 컨텍스트가 DB를 조회해서 실제 Entity 값을 생성해준다

프록시 객체는 실제 엔티티의 getName()을 호출해서 원하는 getName 값을 받을 수 있다.

이후에는 해당 과정없이 사용이 가능하다

 

 

참고

https://ict-nroo.tistory.com/131

 

[JPA] 프록시란?

프록시 질문으로 부터 프록시에 대한 학습을 시작한다. Member 엔티티를 조회할 때 Team도 함께 조회해야 할까? 실제로 필요한 비즈니스 로직에 따라 다르다. 비즈니스 로직에서 필요하지 않을 때

ict-nroo.tistory.com

https://victorydntmd.tistory.com/210

 

[Spring JPA] 프록시( proxy )와 지연로딩

지연로딩이 필요한 이유와 프록시( proxy ) 지연 로딩이란 자신과 연관된 엔티티를 실제로 사용할 때 연관된 엔티티를 조회( SELECCT )하는 것을 말합니다. 반대로 즉시 로딩이란 엔티티를 조회할

victorydntmd.tistory.com

https://www.inflearn.com/course/ORM-JPA-Basic

 

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

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

www.inflearn.com

 

728x90

댓글