JPA 측에서 Entity가 실제로 사용되기 전까지 DB 조회를 지연하는 것을 말한다.
문제는 지연 로딩을 사용하기 위해서는 DB 조회를 하지는 않았지만 필요한 순간 바로 조회하여 저장할 "가짜 객체"가 필요하다는 점인데, 이 객체를 프록시 객체라고 한다.
프록시 객체는 처음 사용할 때 1번만 초기화되고, 프록시 객체를 통해서도 실제 Entity에 접근할 수 있다.
영속성 컨텍스트에 만약 찾는 Entity가 존재할 경우 em.getRefrence()를 통해 프록시 객체를 활용하더라도 실제 Entity가 저장된다는 특징이 있다.
// 엔티티 직접 조회 - 영속성 컨텍스트에 없으면 DB 조회
Member member = em.find(Member.class, 100L);
// 엔티티를 실제 사용하는 시점까지 미루는 프록시 객체
Member member = em.getReference(Member.class, 100L);
@ManyToOne이나 @OneToMany 어노테이션에 fetch라는 Parameter가 존재한다.
FetchType.EAGER일 경우 즉시 로딩, FetchType.LAZY일 경우 지연 로딩이 수행된다.
즉시 로딩(EAGER) 같은 경우 Hibernate는 SQL 조인을 통해 한 번에 조회하고, 지연 로딩(LAZY) 같은 경우 Proxy를 실제로 활용할 때 초기화하면서 DB를 조회하여 데이터를 저장한다.
어노테이션 | 로딩 전략 |
---|---|
@ManyToOne, @OneToOne | 즉시 로딩(FetchType.EAGER) |
@OneToMany, @ManyToMany | 지연 로딩(FetchType.LAZY |
참고로 모든 연관관계에 지연 로딩을 사용하는 것을 추천하며 개발 완료 단계 때 실제 사용 상황을 보며 최적화하는 방식을 추천한다.
Collection에 FetchType.EAGER를 사용하는 것은 그렇게 권장되지는 않는데, 컬렉션 즉시 로딩은 항상 Outer Join을 활용하기 때문에 필요한 것보다 더 많은 데이터를 가지고 오는 경우가 발생하기 때문이다.
특정 Entity를 영속 상태로 만들 때 연관된 엔티티도 동시에 영속 상태로 만들고 싶을 때 활용한다.
CascadeType.PERSIST로 지정할 수 있으며 @OneToMany 쪽에 명시한다.
이를 활용하면 부모와 자식을 한꺼번에 저장할 수 있게 되며 삭제할 때도 부모와 자식을 동시에 삭제할 수 있다.
참고로 CascadeType.REMOVE는 연결이 끊어질 때 자동 삭제한다기보다는 연관 Entity가 삭제될 때 같이 삭제하라는 영속성 전이와 관련된 옵션이다.
JPA는 부모 Entity와 연관관계가 끊어진 자식 Entity를 자동으로 삭제하는 기능을 가진다.
부모 Entity에서 자식 Entity를 삭제만 한다면 부모와 자식 간 참조가 끊어지는 것으로 이해하여 DB 레벨에서도 삭제된다.
DB의 Remove가 CASCADE로 설정되었다고 생각하면 편하다.
@OneToOne에서도 연결이 끊어지면 자동으로 DB에서 삭제한다.
연결이 끊어진 엔티티를 같이 삭제하라는 의미로 Owner 객체와 참조가 끊어진 객체들을 자동으로 삭제시켜야 하는 경우 유용하다.