프록시와 연관관계 관리

Sangkyeong Lee·2021년 5월 19일

[인프런]JPA

목록 보기
7/8

인프런 강의 < 자바 ORM 표준 JPA 프로그래밍 - 기본편 > 정리


프록시

em.find()

JPA에서 식별자로 엔티티 하나를 조회할때 em.find()를 사용하는데 영속성 컨텍스트에 엔티티가 없으면 데이터베이스를 조회한다.

  • 사용여부에 상관없이 무조건 조회하므로 비효율적

em.getReference()

em.getReference()는 엔티티를 실제 사용할때 까지 아무것도 생성하지 않고, 대신 데이터베이스 접근을 위한 프록시 객체를 반환한다.

  • 프록시 객체는 실제 클래스를 상속받아서 만들어지므로 사용자 입장에서는 구분할 필요가 없다.

프록시 객체는 실제 객체에 대한 참조를 보관하며, 프록시 객체의 메소드를 호출하면 실제 객체의 메소드가 호출된다.

프록시 객채 초기화

프록시 객체가 member.genName()처럼 실제 사용될 경우, 데이터베이스를 조회해서 실제 엔티티 객체를 생성하는 것을 말한다.

Member member = em.getReference(Member.class, "id1");
member.getName();

프록시 특징

  1. 프록시 객체는 처음 사용할때 한번만 초기화한다.
  2. 초기화되면 프록시 객체가 실제 엔티티로 바뀌는 것이 아니라 접근 가능해지는것
  3. 실제 엔티티를 상속받는 것이므로 타입 체크할때 ==이 아니라 instance of 사용해야 한다.
  4. 영속성 컨텍스트에 찾는 엔티티가 이미 있을때, em.getReference()를 호출해도 실제 엔티티를 반환한다.
  5. 영속성 컨텍스트의 도움을 받을 수 없는 준영속 상태일 때, 프록시 초기화면 예외가 발생한다.

즉시로딩과 지연로딩

멤버정보를 조회하게 되면 연관되어 있는 Team정보도 조회해야 될까?

fetch = FethcType.LAZY

그럴 필요가 없기 때문에 지연로딩을을 위해 fetch = FetchType.LAZY를 붙여준다.

그렇게 되면 멤버정보만 로딩을 하고 team은 프록시 객체로 된다.

fetch = FetchType.EAGER

만약 멤버와 팀을 매번 거의 같이 사용할 경우 쿼리를 두번씩 날려야 되는 지연로딩보다는 즉시 로딩 할수 있는 즉시 로딩을 사용한다.

결론

  • 가급적 지연 로딩을 사용한다.
  • 즉시로딩을 하면 예상치 못한 SQL이 발생한다.
  • 즉시로딩은 JPQL에서 N+1문제를 일으킨다.
  • @ManyToOne, @OneToone은 기본이 즉시 로딩으로 설정되어 있어서 LAZY로 설정해야 한다.

영속성 전이: CASCADE

특정 엔티티를 영속 상태로 만들 때 연관된 엔티티도 함께 영속 상태로 만들고 싶을때 사용한다.

  • 만약 하나의 부모가 있고 자식이 두명 있다고 했을때 부모, 자식1, 자식2 저장을 위해 총 세번의 persist가 발생한다.
  • 이 때 총 세번하지 말고 부모만 영속화시키면 연관된 자식들도 모두 영속화된다.

고아 객체(ORPHAN)

부모 엔티티와 연관관계가 끊어진 자식 엔티티를 자동으로 삭제하는 기능을 제공하는데 이 기능을 ORPHAN 제거라고 한다.

Parent parent1 = em.find(Parent.class, id);
parent1.getChildren().remove(0);// 자식 엔티티를 컬렉션에서 제거

orphanRemoval = true 라는 옵션을 이용한 다음 컬렉션에서 엔티티를 제거하면 데이터베이스의 데이터도 삭제된다.

결론

고아 객체 제거는 참조가 제거된 엔티티는 다른 곳에서 참조하지 않는 고아 객체로 보고 삭제하는 기능이며 참조하는 곳이 하나일때만 사용해야 한다.

따라서 @OneToOne, @OneToMany 에서만 사용한다.

CascadeType.ALL + orphanRemoval = true 를 모두 사용하면 스스로 생명주기를 관리하는 em.persist()로 영속화 em.remove()로 제거하는데 두 기능을 모두 사용하면 자식의 생명주기도 관리할 수 있게된다.


< 자료 출처: 자바 ORM 표준 JPA 프로그래밍 - 기본편 >

profile
💻Backend Developer

0개의 댓글