프록시와 연관관계 관리

Timo·2021년 4월 19일
0
post-thumbnail

김영한님의 <자바 ORM 표준 JPA 프로그래밍> 책을 정리한 내용입니다.

프록시

프록시를 사용하면 연관된 객체를 처음부터 데이터베이스에서 조회하는 것이 아니라, 실제 사용하는 시점에 데이터베이스에서 조회할 수 있다.
하지만 자주 함께 사용하는 객체들은 조인을 사용해서 함께 조회하는 것이 효과적이다.
JPA는 즉시 로딩과 지연 로딩이라는 방법으로 둘을 모두 지원한다.

  • 지연 로딩: 엔티티가 실제 사용될 때까지 데이터베이스 조회를 지연하는 방법

지연 로딩 기능을 사용하려면 실제 엔티티 객체 대신에 데이터베이스 조회를 지연할 수 있는 가짜 객체가 필요한데 이것을 프록시 객체라 한다.

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

Member member = em.find(Member.class, “member1”);

이렇게 엔티티를 직접 조회하면 조회한 엔티티를 실제 사용하든 사용하지 않든 데이터베이스를 조회하게 된다.

엔티티를 실제 사용하는 시점까지 데이터베이스 조회를 미루고 싶으면 EntityManager.getReference() 메소드를 사용하면 된다.

Member member = em.getReferences(Member.class, “member1”);

이 메소드를 호출할 때 JPA는 데이터베이스를 조회하지 않고 실제 엔티티 객체도 생성하지 않는다.
대신에 데이터베이스 접근을 위임한 프록시 객체를 반환한다.

프록시 객체의 초기화

프록시 객체는 member.getName()처럼 실제 사용될 때 데이터베이스를 조회해서 엔티티 객체를 생성하는데 이것을 프록시 객체의 초기화라 한다.

  • 프록시 객체를 초기화한다고 프록시 객체가 실제 엔티티로 바뀌는 것은 아니다.
프록시로 객체가 초기화되면 프록시 객체를 통해서 실제 엔티티에 접근할 수 있다.
  • 영속성 컨텍스트에 찾는 엔티티가 이미 있으면 데이터베이스를 조회할 필요가 없으므로
em.getReference()를 호출해도 프록시가 아닌 실제 엔티티를 반환한다.

즉시 로딩과 지연 로딩

  • 즉시 로딩: 엔티티를 조회할 때 연관된 엔티티도 함께 조회한다.
    설정 방법: @ManyToOne(fetch = FetchType.EAGER)
  • 지연 로딩: 연관된 엔티티를 실제 사용할 때 조회한다.
    설정 방법: @ManyToOne(fetch = FetchType.LAZY)

즉시 로딩

대부분의 JPA 구현체는 즉시 로딩을 최적화하기 위해 가능하면 조인 쿼리를 사용한다.

@JoinColum 속성으로 nullable = false를 지정하면 내부 조인을 사용하고, true(기본값)를 사용하면 외부 조인을 사용한다.
@ManyToOne 어노테이션 속성으로 optional = false를 설정해도 내부 조인을 사용한다.

지연 로딩 활용

JPA의 기본 페치(fetch) 전략은 연관된 엔티티가 하나면 즉시 로딩을, 컬렉션이면 지연 로딩을 사용한다.

컬렉션에 FetchType.EAGER 사용 시 주의점

  • 컬렉션을 하나 이상 즉시 로딩하는 것은 권장하지 않는다.
  • 컬렉션 즉시 로딩은 항상 외부 조인을 사용한다.

영속성 전이: CASCADE

특정 엔티티를 영속 상태로 만들 때 연관된 엔티티도 함께 영속 상태로 만들고 싶으면 영속성 전이 기능을 사용하면 된다.
JPA는 CASCADE 옵션으로 영속성 전이를 제공한다.

연관관계 어노테이션(ex. @OneToMany)에 cascade 속성으로 PERSIST, REMOVE, ALL 등을 지정할 수 있다.

고아 객체

JPA는 부모 엔티티와 연관관계가 끊어진 자식 엔티티를 자동으로 삭제하는 기능을 제공하는데 이것을 고아 객체(ORPAHN) 제거라 한다.

이 기능을 사용해서 부모 엔티티의 컬렉션에서 자식 엔티티의 참조만 제거하면 자식 엔티티가 자동으로 삭제된다.

연관관계 어노테이션(ex. @OneToMany)에 orphanRemoval 속성 값으로 true, false를 명시하여 사용한다.

영속성 전이 + 고아 객체, 생명 주기

CascadeType.ALL + orpahnRemoval = true를 동시에 사용하면 부모 엔티티를 통해서 자식의 생명주기를 관리하게 된다.

자식을 저장하려면 부모에 등록만 하면 된다(CASCADE)

Parent parent = em.find(Parent.class, parentId);
parent.addChild(child1);

자식을 제거하려면 부모에서 제거하면 된다(orphanRemoval)

Parent parent = em.find(Parent.class, parentId);
parent.getChildren().remove(removeObject);
profile
나는 매일 성장하는 사람

0개의 댓글