Notice
Recent Posts
Recent Comments
Link
«   2024/12   »
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30 31
Archives
Today
Total
관리 메뉴

개발 기록지

[JPA] 즉시로딩과 지연로딩 프록시의 이해 본문

JPA

[JPA] 즉시로딩과 지연로딩 프록시의 이해

hyeonw777 2021. 7. 6. 17:18

즉시로딩이란?

엔티티를 조회할 때 연관된 엔티티를 조인하여 전부 가져온다. 쿼리 한 번으로 모든 정보를 가져와 참조가 많아질수록 조인이 많아지게 되고 이로 인해 성능상 문제가 될 수 있다.

지연로딩이란?

엔티티를 조회할 때 연관된 엔티티를 항상 사용하는 것은 아니다. 예를 들어 Member엔티티를 조회할 때 연관된 Team엔티티까지 모두 조회가 된다면 성능상 문제가 발생할 것이다. 지연로딩은 즉시로딩과 달리 연관된 엔티티가 실제로 사용될 때 쿼리가 날아간다. 따라서 상황에 따라 쿼리가 여러 번 날아간다.

  • 지연로딩(LAZY):  연관된 엔티티를 실제 사용할 때 조회한다. 
  • 즉시로딩(EAGER):  엔티티를 조회할 때 쿼리 한 번으로 연관된 엔티티를 전부 조인을 통해 조회한다.

지연로딩의 이해와 프록시 객체

지연로딩을 사용하기 위해서는 프록시 객체를 사용해야 한다. 프록시 객체는 실제 엔티티 객체 대신에 데이터베이스 조회를 지연시킨다. 프록시 객체는 실제 엔티티 클래스를 상속받아 만들어지므로 실제 엔티티 클래스와 겉모양은 같다.

Member member = em.find(Member.class, "member1") //실제 엔티티 객체를 조회

Member member = em.getReference(Member.class, "member1") //데이터베이스 접근을 위임한 프록시객체반환

 

EntityManager.find()는 실제 엔티티 객체를 조회하여 데이터베이스에 쿼리가 바로 나간다. EntityManager.getReference() 메소드를 사용해 얻은 프록시 객체는 하이버네이트가 만든 프록시 객체로 member.getName() 처럼 실제 사용될 때 데이터베이스에 쿼리를 날리고 실제 엔티티 객체를 생성한다.

프록시의 특징

  • 프록시 객체는 실제 엔티티 클래스를 상속받아 만들어져 겉 모양이 같다.
  • 프록시 객체는 실제 객체(엔티티)에 대한 참조를 보관한다.
  • 프록시 객체의 메서드를 호출하면 프록시 객체는 실제 객체의 메소드를 호출한다.
  • 프록시 객체는 실제 데이터를 사용하는 시점에 쿼리가 날아간다. 

프록시 객체 초기화 과정

프록시 객체는 member.getName()처럼 실제 사용될 때 데이터베이스에 쿼리를 날린다. 이때 실제 엔티티가 생성되어 있지 않으면 영속성 컨텍스트에 생성 요청을 보내고 이것을 초기화라 한다.

영속성 컨텍스트에 실제 엔티티가 생성되어 있을 때 실제 엔티티 반환

 

영속성 컨텍스트에 실제 엔티티가 없을 때 프록시 객체 반환

위의 코드처럼 영속성 컨텍스트에 실제 엔티티가 있다면 데이터베이스에 조회할 필요가 없으므로 getReference()를 호출할 때 실제 엔티티를 반환한다. 이처럼 프록시 객체는 연관된 엔티티를 지연로딩할 때 사용한다.

즉시로딩시 조인 전략

즉시로딩으로 Member를 조회할때 Team도 함께 조회된다. 즉시로딩은 조회할 때 한 번의 쿼리로 조인해서 데이터를 가져오는데 이때 외래 키의 조건(NOT NULL, NULL)에 따라 외부 조인 또는 내부 조인이 발생한다.  외래 키가 NULL을 허용할 시 외부 조인이 발생하고 NOT NULL 조건 시 내부 조인이 발생한다. 조인 전략은 내부 조인보다 외부 조인이 성능상 더 좋기 때문에 NOT NULL 조건이라면 @JoinColumn에 nullable = false을 설정하여 내부조인을 사용하도록 한다.

  • @joinColumn(nullable = true) : NULL 허용, 외부 조인 사용
  • @joinColumn(nullable = true) : NULL 허용하지 않음, 내부 조인 사용

지연로딩 vs 즉시로 

그렇다면 지연로딩을 써야 할까? 즉시로딩을 써야 할까? 이 물음에 답은 상황에 따라 다르다. 지연로딩은 조인을 쓰지 않지만 여러 번의 쿼리문이 날아갈 수 있고 즉시로딩은 쿼리를 한 번만 날리지만 다량의 조인이 발생할 수 있다. 테이블이 복잡하고 연관관계가 깊어질수록 참조 객체는 많을 것이고 이 상황에서 즉시로딩을 쓴다면 다량의 조인을 발생시켜 성능상 문제가 일어나고 예상치 못한 쿼리가 발생할 수 있다. 하지만 회원과 팀 엔티티를 같이 사용한다면 조인을 사용해 한 번에 조회하는 것이 더 효율적일 수 있다. 

 

 

 

'JPA' 카테고리의 다른 글

[JPA] 영속성 전이 : CASCADE  (0) 2021.07.11
Comments