해당 시리즈는 김영한님의 JPA 로드맵을 따라 학습하면서 내용을 정리하는 글입니다
em.find()
vs em.getReference()
em.find()
: 데이터 베이스를 통해서 실제 엔티티 객체 조회em.getReference()
: 데이터베이스 조회를 미루는 가짜(프록시) 엔티티 조회getReference
하는 시점에는 쿼리를 날리지 않다가 실제로 사용하는 시점에서 쿼리를 날려서 데이터베이스에서 가져옵니다target
)를 보관합니다Member member = em.getReference(Member.class, "id1");
member.getName();
getName
이 호출되는 시점에 영속성 컨텍스트에 요청을 합니다target
에 실제 객체를 매핑해 줍니다em.getReference()
를 호출해도 실제 엔티티 반환JPA
에서는 같은 트랜잭션에서 타입이 같은 두 객체를 비교할 때(==
) 무조건 true
를 보장하기 때문에 이미 영속성 컨텍스트에 있으면 프록시 객체를 생성하지 않고 실제 엔티티를 반환합니다하이버네이트
는 org.hibernate.LazyInitializationException
예외를 터트립니다)PersistenceUnitUtil.isLoaded(Object entity)
EntityManagerFactory emf = Persistence.createEntityManagerFactory(...);
emf.getPersistenceUnitUtil().isLoaded(entity);
entity.getClass().getName()
출력org.hibernate.Hibernate.initialize(entity);
JPA
표준은 강제 초기화가 없습니다member.getName()
등으로 초기화 유도System.out.println(member.getName());
@Entity
public class Member {
...
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "TEAM_ID")
private Team team;
...
}
Team
객체는 프록시 객체로 조회하게 됩니다Team
객체를 사용하는 시점에 쿼리를 조회해서 진짜 Team
의 엔티티로 교체됩니다@Entity
public class Member {
...
@ManyToOne(fetch = FetchType.EAGER)
@JoinColumn(name = "TEAM_ID")
private Team team;
...
}
Member
객체를 조회해서 사용할 때 많은 경우 Team
객체를 같이 사용하는 로직이 대부분이라면 EAGER
옵션을 통해서 즉시로딩을 하는게 좋습니다(두 번의 쿼리가 안나갈 수 있기 때문입니다)SQL
이 발생합니다JOIN
이 발생할 수 있습니다JPQL
에서 N + 1
문제를 일으킵니다 List<Member> members = em.createQuery("select m from Member m", Member.class)
.getResultList();
JPQL
은 SQL
로 번역되고 실행됩니다. 따라서 위 코드도 SQL
로 번역되고 쿼리문 대로 Member
만 선택하게 됩니다. 하지만 설정에 EAGER
로 되어있으면 즉시로딩이기 때문에 한번 더 쿼리를 보내서 Member
마다 연결된 Team
의 정보까지 불러오는 겁니다. 원치않게 쿼리가 두번 실행되게 됩니다@ManyToOne, @OneToOne
은 기본이 즉시 로딩입니다 -> LAZY로 설정해야 합니다@OneToMany, @ManyToMany
는 기본이 지연 로딩입니다JPQL
fetch
조인이나, 엔티티 그래프 기능을 사용하도록 합니다orphanRemoval = true
Parent parent1 = em.find(Parent.class, id);
parent1.getChildren().remove(0);
// 자식 엔티티를 컬렉션에서 제거
DELETE FROM CHILD WHERE ID=?
@OneToOne
, @OneToMany
만 가능CascadeType.REMOVE
처럼 동작합니다em.persist()
로 영속화하고, em.remove()
를 통해서 제거합니다Aggregate Root
개념을 구현할 때 유용합니다