em.find()
vs em.getReference()
em.find()
: 데이터베이스를 통해서 실제 엔티티 객체 조회em.getReference()
: 데이터베이스 조회를 미루는 가짜(프록시) 엔티티 객체 조회
실제 클래스를 상속 받아서 만들어짐
Member member = em.getReference(Member.class, “id1”);
member.getName();
member.getClass()
를 봐도 여전히 프록시 객체임instance of
사용)
em.find()
등으로 실제 엔티티를 조회하면 뒤에 조회된 객체도 프록시 타입이 들어간다. 대신 내부에서 프록시 초기화가 실행되어 실제 값을 가져올 수 있다.em.getReference()
를 호출해도 실제 엔티티 반환(하이버네이트는 org.hibernate.LazyInitializationException
예외를 터트림)
프록시 인스턴스의 초기화 여부 확인
PersistenceUnitUtil.isLoaded(Object entity)
프록시 클래스 확인 방법
entity.getClass().getName()
출력(..javasist.. or HibernateProxy…)
프록시 강제 초기화
org.hibernate.Hibernate.initialize(entity);
참고: JPA 표준은 강제 초기화 없음
강제 호출: member.getName()
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "TEAM_ID")
private Team team;
Member member = em.find(Member.class, 1L);
Team team = member.getTeam();
team.getName();
// 실제 team을 사용하는 시점에 초기화(DB 조회)
@ManyToOne(fetch = FetchType.EAGER)
@JoinColumn(name = "TEAM_ID")
private Team team;
• JPA 구현체는 가능하면 조인을 사용해서 SQL 한번에 함께 조회
@ManyToOne
, @OneToOne
은 기본이 즉시 로딩 → LAZY로 설정@OneToMany
, @ManyToMany
는 기본이 지연 로딩즉시 로딩일 때
em.find(Member.class, id);
em.find()
로 찾을 때는 JPA가 내부적으로 최적화를 할 수 있다.em.createQuery(“select m from Member m”, Member.class)
em.createQuery(“select m from Member m”, Member.class)
실행select m.* from member
@Entity
public class Parent {
@OneToMany(mappedBy="parent", cascade=CascadeType.PERSIST)
private List<Child> childList = new ArrayList<>();
em.persist(parent);
em.persist(child1);
em.persist(child2);
em.persist(parent)
하나로 child1, 2까지 영속이 가능하다.
ALL
: 모두 적용PERSIST
: 영속REMOVE
: 삭제주의! – 자식의 소유자가 하나일 때만 cascade 옵션을 사용해야 한다. (부모 엔티티에게 완전히 종속적일 때(단일 소유자), 라이프 사이클이 똑같을 때) 부모 외에도 다른 엔티티가 자식과 연관관계가 있다면 쓰면 안된다. 자식이 다른 엔티티를 참조하는 건 상관 없는데, 다른 엔티티가 부모가 아님에도 자식을 참조하면 운영이 많이 힘들어진다.
@OneToMany(mappedBy="parent", cascade=CascadeType.ALL, orphanRemoval = true)
private List<child> childList = new ArrayList();
Parent parent1 = em.find(Parent.class, id);
parent1.getChildren().remove(0);
//자식 엔티티를 컬렉션에서 제거
DELETE FROM CHILD WHERE ID=?
@OneToOne
, @OneToMany
만 가능CascadeType.REMOVE
처럼 동작한다CascadeType.ALL
+ orphanRemovel=true
em.persist()
로 영속화, em.remove()
로 제거em.persist()
, em.remove()
를 호출하지 않아도 부모에서 호출하는 시점에 영속성이 전이가 되어 부모와 자식이 생명 주기를 공유