영속성 전이(CASCADE)
- 특정 엔티티를 영속 상태로 만들 때 연관된 엔티티도 함께 영속 상태로 만들고 싶은 경우 사용한다.
- ex) 부모 엔티티를 저장할 때 자식 엔티티도 함께 저장하고 싶다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
@Entity
public class Parent {
@Id @GeneratedValue
private Long id;
private String name;
@OneToMany(mappedBy = "parent")
private List<Child> childList = new ArrayList<>();
public void addChild(Child child) {
childList.add(child);
child.setParent(this);
}
//...
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
@Entity
public class Child {
@Id @GeneratedValue
private Long id;
private String name;
@ManyToOne
@JoinColumn(name = "parent_id")
private Parent parent;
//...
}
위와 같이 엔티티 코드를 작성했을 때
1
2
3
4
5
6
7
8
9
10
11
Child child1 = new Child();
Child child2 = new Child();
Parent parent = new Parent();
parent.addChild(child1);
parent.addChild(child2);
em.persist(parent);
em.persist(child1);
em.persist(child2);
단순히 parent만 persist() 해주는 것이 아닌 child도 하나하나 persist() 해주어야 의도한 대로 DB에 반영된다.
객체 입장에서는 parent 위주로 코드를 작성했는데 child도 신경써주어야 되는 것이다.
1
2
@OneToMany(mappedBy = "parent", cascade = CascadeType.ALL)
private List<Child> childList = new ArrayList<>();
이럴 때 영속성 전이(cascade)를 사용하면 parent만 persist() 해주어도 의도한 대로 child까지 persist() 되는 것을 볼 수 있다.
- 영속성 전이는 연관관계를 매핑하는 것과 아무런 관계가 없다.
- 엔티티를 영속화할 때 연관된 엔티티도 함께 영속화하는 편리함을 제공할 뿐이다.
주의
- 부모와 자식간의 라이프 싸이클(등록 및 삭제 등)이 유사할 때 사용한다.
- 그리고 parent같이 child를 소유하는 객체가 단 하나일때만 사용한다.
- ex) 게시글과 첨부 파일의 관계
- 만약 child가 위와 같이 parent와도 관련이 되어 있고, Member와도 관련이 되어 있으면 사용하면 안된다.
CASCADE의 종류
- ALL: 모두 적용
- PERSIST: 영속
- REMOVE: 삭제
- MERGE: 병합
- REFRESH: REFRESH
- DETACH: DETACH
고아 객체
- 부모 엔티티와 연관관계가 끊어진 자식 엔티티
부모 엔티티와 연관관계가 끊어진 자식 엔티티를 자동으로 삭제할 경우 사용한다.
1
2
@OneToMany(mappedBy = "parent", cascade = CascadeType.ALL, orphanRemoval = true)
private List<Child> childList = new ArrayList<>();
- orphanRemoval = true
- Parent parent1 = em.find(Parent.class, id); parent1.getChildren().remove(0);
- DELETE FROM CHILD WHERE ID = ?
주의
- 참조가 제거된 엔티티는 다른 곳에서 참조하지 않는 고아 객체로 보고 삭제하는 기능이다.
- 참조하는 곳이 하나일때만 사용한다.
- 특정 엔티티가 개인 소유할 때 사용한다.
- @OneToOne, @OneToMany만 가능하다.
참고: 개념적으로 부모를 제거하면 자식은 고아가 된다. 따라서 고아 객체 제거 기능을 활성화하면 부모를 제거할 때 자식도 함께 제거된다.
이는 CascadeType.REMOVE 처럼 동작한다.
영속성 전이 + 고아 객체, 생명 주기
- CascadeType.ALL + orphanRemoval = true
- 이 두 옵션을 모두 활성화하면 부모 엔티티를 통해 자식의 생명 주기를 관리할 수 있다.
- Parent만 persist 혹은 remove를 하면 자식도 동일한 생명 주기를 가진다.
- 도메인 주도 설계(DDD)의 Aggregate Root 개념을 구현할 때 유용하다.
가장 중요한 것은 영속성 전이나 고아 객체 전부 특정 엔티티가 개인 소유할 때 사용해야 한다는 것이다.