[JPA] 영속성 전이, 고아 객체 (cascade 범위)
JPA 영속성 전이
JPA는 CASCASE 옵션으로 영속성 전이를 제공한다.
JPA 영속성 전이란, 특정 엔티티를 영속 상태로 만들 때 연관된 엔티티도 함께 영속 상태가 되게(영속화), 혹은 함께 삭제가 이뤄지게 하는 것이다. 쉽게 말해서 영속성 전이를 사용하면 부모 엔티티를 저장할 때 자식 엔티티도 함께 저장할 수 있다.
위와 같이 Parent와 Child가 일대다 관계를 맺었다고 하고 부모쪽에서 cascade옵션을 설정해보자.
@Entity
public class Parent {
@Id @GeneratedValue
private Long id;
@OneToMany(mappedBy = "parent", cascade = CascadeType.PERSIST)
private List<Child> children = new ArrayList<Child>();
...
}
@Entity
public class Child {
@Id @GeneratedValue
private Long id;
@OneToMany
private Parent parent;
...
}
만약 부모 1명에 자식 2명을 저장한다면 다음과 같은 코드를 작성할 것이다.
private static void saveNoCascade(EntityManager em) {
Parent parent = new Parent();
em.persist(parent);
// 1번 자식 저장
Child child1 = new Child();
child1.setParent(parent); //자식->부모 연관관계 설정
parent.getChildren().add(child1);
em.persist(child1);
// 2번 자식 저장
Child child2 = new Child();
child1.setParent(parent); //자식->부모 연관관계 설정
parent.getChildren().add(child1);
em.persist(child2);
}
JPA에서 엔티티를 저장할 때 연관된 모든 데이터는 영속 상태여야 한다. 지금처럼 자식 엔티티와 부모 엔티티 모두 영속 상태로 만들고 싶을때 사용하면 되는 것이 영속성 전이이다.
Cascade에는 많은 옵션이 있지만 일단은 PERSIST로 설정해 영속화가 함께 일어나도록 한다.
@OneToMany(mappedBy="parent", cascade=CascadeType.PERSIST)
private List<Child> childList = new ArrayList<>();
이러면 부모 객체를 만들어 영속화만 해줘도 함께 관계를 만들어준 자식객체도 영속화가 된다. 연관관계인 두 엔티티 사이에서 쓰면 편리하다. Cascade 종류는 PERSIST 말고도 ALL, REMOVE, MERGE, DETACH 등이 있는데 상황에 따라 사용하면 된다.
Cascade 범위는 관계에서 주인이 private owner일 때 (다른게 참조할 수 없는 경우..), 라이프 사이클에 대해 동일할 때 쓰면 좋다. 무분별하게 사용하다보면 지워지지 말아야 할 것도 지워지고 막 그렇다..
고아 객체
부모엔티티와 관계가 끊어진 자식엔티티를 고아객체라고 한다. orphanRemoval = true 옵션을 설정해주면 이런 고아객체를 자동으로 삭제할 수 있다. 아래와 같이 parent의 children list에서 첫번째 자식을 제거하면..
@OneToMany(mappedBy="parent", cascade=CascadeType.PERSIST, orphanRemoval=true)
private List<Child> childList = new ArrayList<>();
Parent parent1 = em.find(Parent.class, id);
parent1.getChildren().remove(0);
더이상 parent1과 그 자식엔티티는 관계를 맺지 않는다. 따라서 해당 자식엔티티를 삭제하는 delete쿼리가 날아간다.
* cascade REMOVE 와의 차이점?
orhanRemoval은 관계 여부에 따라 달라지기 때문에, 자식엔티티가 삭제된게 아니더라도 부모와 관계가 끊어지면 지워진다. 물론 부모엔티티가 지워져도 연결된 자식 엔티티들과 관계가 끊어지는 것이기 때문에 자식엔티티들도 삭제된다. orphanRemoval이 cascade remove보다 큰 개념.
고아객체 자동 삭제(orphanRemoval = true) 설정은 자식엔티티가 해당 부모엔티티랑만 관계를 맺을 때 사용해야한다. 그렇지 않으면 다른 관계들도 삭제가 되기때문이다. 그리고 관계가 끊어져도 자식엔티티가 존재해야하는 상황에서는 사용하면 안된다.
영속성전이 + 고아객체
영속성전이를 ALL로 하고 orphanRemoval옵션도 켜놓으면 부모엔티티를 통해서 자식엔티티의 생명주기를 조절할 수 있다. 부모엔티티와 자식의 생명주기를 어느정도 맞추고 싶은경우 두개를 함께 사용하면 좋다.
참고: