김영한님의 <자바 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()처럼 실제 사용될 때 데이터베이스를 조회해서 엔티티 객체를 생성하는데 이것을 프록시 객체의 초기화라 한다.
- 즉시 로딩: 엔티티를 조회할 때 연관된 엔티티도 함께 조회한다.
설정 방법: @ManyToOne(fetch = FetchType.EAGER)- 지연 로딩: 연관된 엔티티를 실제 사용할 때 조회한다.
설정 방법: @ManyToOne(fetch = FetchType.LAZY)
대부분의 JPA 구현체는 즉시 로딩을 최적화하기 위해 가능하면 조인 쿼리를 사용한다.
@JoinColum 속성으로 nullable = false를 지정하면 내부 조인을 사용하고, true(기본값)를 사용하면 외부 조인을 사용한다.
@ManyToOne 어노테이션 속성으로 optional = false를 설정해도 내부 조인을 사용한다.
JPA의 기본 페치(fetch) 전략은 연관된 엔티티가 하나면 즉시 로딩을, 컬렉션이면 지연 로딩을 사용한다.
컬렉션에 FetchType.EAGER 사용 시 주의점
특정 엔티티를 영속 상태로 만들 때 연관된 엔티티도 함께 영속 상태로 만들고 싶으면 영속성 전이 기능을 사용하면 된다.
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);