연관관계가 존재하는 엔티티는 조회할 때마다 값을 모두 들고 와야할까?
필요 값들에 대해서만 값을 조회한 뒤, 연관된 엔티티를 사용하려 할 때, 다시 값을 조회한다면 충분히 효율적일 것이다. 이같은 방법을 JPA에서는 지연로딩이라 칭한다.
이 지연로딩을 사용하기 위해, 사용하기 전까지 연관된 엔티티 객체를 채워넣는 가각체를 프록시라 한다.
프록시 객체는 참조 대상의 실제 클래스를 상속받아 만들어진다. 이 프록시 객체로 엔티티를 채워넣은 후, 사용자가 엔티티 객체를 사용하려할 때, DB를 조회한 뒤 실제 엔티티 객체를 생성한다. 이를, 프록시 객체의 초기화라 한다.
전반적인 흐름은 아래와 같다
프록시는 조회할 때 전달한 pk를 보관하고 있는데, 이때문에 pk를 조회하는 과정에서는 엔티티 접근 방식에 따라 프록시 초기화가 일어나지 않는다.
@Access(AccessType.PROPERTY)
: 초기회 일어나지 않음@Access(AccessType.FILED)
: getId가 어떤 필드만 조회하는지 알 수 없어 초기화 발생프록시 인스턴스가 초기화되었는지 여부를 확인하는 메소드를 제공한다.
ex)
boolean isLoad = em.getEntityManagerFactory()
.getPersistenceUnitUtil().isLoaded(entity);
...
프록시를 사용하여 어떻게 연관된 엔티티에 대해 필요할 때, 초기화를 할 수 있는지 알아보았다. 이제 이를 활용한 즉시 로딩과 지연 로딩을 살펴본다.
@nTon의 속성에서 fetch value값을 EAGER로 설정해준다.
@Entity
public class member{
...
@ManyToOne(fetch = FetchType.EAGER)
@JoinColumn(name = "TEAM_ID")
private Team team;
...
}
외래 키에서 null 허용이 적용된다면, 데이터 조회를 위해 outer join을 사용하게 된다. 성능상의 이슈를 해결하기 위해 inner join을 사용하고 싶다면 not null 제약조건을 걸어두자
@nTon의 속성에서 fetch value값을 Lazy로 설정해준다.
@Entity
public class member{
...
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "TEAM_ID")
private Team team;
...
}
특정 엔티티를 영속 상태로 만들 때, 연관 엔티티도 동기화하기 위해 사용한다. 즉, 부모 엔티티를 저장할 때 자식 엔티티도 함께 저장한다
@Entity
public class Parent{
...
@OneToMany(mappedBy = "parent", cascade = CascadeType.PERSIST)
private List<Child> children = new ArrayList<Child>();
...
}
부모 엔티티와 연관관계가 끊어진 객체를 고아 객체라 하는데, 이를 자동으로 제거하는 기능을 고아 객체 제거라 한다. 부모 엔티티에서 자식 엔티티 연관관계를 끊었을 때, 자동으로 제거되는 설정을 알아본다.
@Entity
public class Parent{
...
@OneToMany(mappedBy = "parent", orphanRemoval = true)
private List<Child> children = new ArrayList<Child>();
...
}
참고 도서