엔터티를 조회할 때 연관된 엔터티들이 항상 사용되는 것은 아니다.
JPA는 이런 문제를 해결하려고 엔터티가 실제 사용될 때까지 데이터베이스 조회를 지연하는 방법을 제공하는데 이것을 지연 로딩이라고 한다.
그런데 지연 로딩 기능을 사용하려면 실제 엔터티 객체 대신에 데이터베이스 조회를 지연할 수 있는 가짜 객체가 필요한데 이것을 프록시 객체라 한다.
PersistenceUnitUtil.isLoaded(Object entity)
entity.getClass().getName()
출력org.hibernate.Hibernate.initialize(entity);
+ JPA 표준은 강제 초기화 없음 -> 강제로 초기화하려면 강제 호출을 해야함(member.getName()
)
프록시 객체는 주로 연관된 엔터티를 지연 로딩할 때 사용한다.
JPA는 개발자가 연관된 엔터티의 조회 시점을 선택할 수 있도록 다음 두 가지 방법을 제공한다.
모든 연관관계에 지연 로딩을 사용하고, 꼭 필요한 곳에만 즉시 로딩을 사용하는 것을 추천한다.
특정 엔터티를 영속 상태로 만들 때 연관된 엔터티도 함께 영속 상태로 만들 때 사용하는 것이 영속성 전이이다.
다시 말해 영속성 전이를 사용하면 부모 엔터티를 저장할 때 자식 엔터티도 같이 저장할 수 있다.
JPA에서 엔터티를 저장할 때 연관된 모든 엔터티는 영속 상태여야 한다.
일반적으로 CASCADE는 연관관계의 주인에 반대쪽에 설정한다.
CASCADE는 다음처럼 여러 속성을 같이 사용할 수 있다.
cascade = {CascadeType.PERSIST, CascadeType.REMOVE}
+ CascadeType.PERSIST와 CascadeType.REMOVE는 em.persist(), em.remove()를 실행할 때 바로 전이가 발생하지 않고, 플러시를 호출할 때 전이가 발생한다.
JPA에서 부모 엔터티와 연관관계가 끊어진 자식 엔터티를 자동으로 삭제하는 기능을 고아 객체 제거라 한다.
고아 객체 정리
+ 고아 객체 제거는 추가적으로 CascadeType.REMOVE와 같은 기능을 제거한다.
CascadeType.ALL, orphanRemoval = true
를 동시에 사용하면 엔터티 스스로 생명주기를 관리한다는 뜻이다. 두 옵션을 모두 활성화하면 부모 엔터티를 통해 자식의 생명주기를 관리할 수 있다.
처음에는 고아 객체 제거가 Cascade.REMOVE와 같은 기능을 한다고 잘못 이해해서 CascadeType.ALL을 설정하면 굳이 고아 객체 기능도 설정해줘야 할까 하는 의문이 생겼다.
하지만 교재를 천천히 살펴보니 둘이 같은 기능을 하는 것이 아닌, 고아 객체 제거에서 추가적으로 CascadeType.REMOVE 기능을 제공하는 것이었다.
그럼 CascadeType.REMOVE와 고아 객체 제거는 정확히 어떻게 다른 것일까?
CascadeType.REMOVE는 부모 객체가 제거되면 부모 객체 아래 있는 자식 객체도 같이 제거되는 것이다.
반면 고아 객체 제거는 부모 객체는 살아있되, 그 안에서 자식을 삭제하면 부모 객체와 자식 객체 간의 연관관계가 끊어지게 되므로 이 끊어진 자식 엔터티를 제거해주는 것이다.
이때 개념적으로 부모가 제거되어도 자식들은 연관관계가 끊어지므로 제거되는데 이것이 CascadeType.REMOVE와 같다는 것이다.