cascade : 영속성 전이
- JPA에서 Cascade 옵션을 사용하면 특정 엔티티를 영속 상태로 만들 때 연관된 엔티티도 함께 영속 상태로 만들 수 있다.
- 엔티티를 영속화할 때 연관된 엔티티도 함께 영속화하는 편리함을 제공한다.
@Entity
public class Parent {
@Id
@GeneratedValue
private Long id;
//cascade 옵션 적용
@OneToMany(mappedBy = "parent", cascade = CascadeType.ALL)
private List<Child> childList = new ArrayList<>();
public List<Child> getChildList() {
return childList;
}
public Long getId() {
return id;
}
}
@Entity
public class Child {
@Id
@GeneratedValue
private Long id;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "parent_id")
private Parent parent;
protected Child() {
}
public Child(Parent parent) {
this.parent = parent;
}
}
Parent엔티티의 childList를 보면 cascade 옵션이 적용되어있는 것을 볼 수 있다. 이렇게 되면 parent만 영속화하여도 cascade 옵션으로 인해 영속성 전이가 일어나 childList에 저장되어 있는 Child 엔티티들도 영속화가 된다.
Parent parent = new Parent();
Child child1 = new Child(parent);
Child child2 = new Child(parent);
parent.getChildList().add(child1);
parent.getChildList().add(child2);
em.persist(parent);
위와 같이 parent에 대해서만 persist 메서드를 호출하였음에도 불구하고, child 들도 insert 쿼리가 나가는 것을 볼 수 있다.
Hibernate:
/* insert hello.Parent */
insert into Parent(id) values (?)
Hibernate:
/* insert hello.Child */
insert into Child (parent_id, id) values (?, ?)
Hibernate:
/* insert hello.Child */
insert into Child (parent_id, id) values (?, ?)
cascade 옵션에 넣을 수 있는 값들은 다음과 같다.
- ALL : 모두 적용
- PERSIST : 영속
- REMOVE : 삭제
- MERGE : 병합
- REFRESH
- DETACH : 준영속
이 값들의 의미는 다음과 같다. EntityManager.XX 메서드를 실행했을 때 연관된 엔티티의 cascade 옵션에 XX 값이 적용되어 있다면 해당 옵션이 적용된 엔티티도 같이 XX 작업을 하겠다는 뜻이다.
예를 들어 A라는 특정 엔티티와 연관된 B라는 엔티티의 cascade 옵션이 PERSIST로 적용되어 있다면, A 엔티티를 대상으로 EntityManager.persist(A)가 호출될 때 B도 같이 EntityManager.persist(B)가 호출되는 것이다.
cascade 옵션은 부모 엔티티가 단일 소유자일 때, 부모와 자식의 라이프 사이클이 유사할 때 사용하는 것이 좋다.
orphanRemoval : 고아 객체 제거
orpahnRemoval 옵션을 사용해서 부모 엔티티와 연관관계가 끊어진 자식 엔티티를 자동으로 삭제하도록 할 수 있다.
- 특정 엔티티가 단일 소유할 때, 참조하는 곳이 하나일 때 사용
- @OneToOne, @OneToMany만 사용 가능
- 추가적으로 부모를 제거할 때 자식도 같이 제거된다.(CascadeType.REMOVE와 유사)
@OneToMany(mappedBy = "parent", cascade = CascadeType.ALL, orphanRemoval = true)
private List<Child> childList = new ArrayList<>();
orphanRemoval = true 를 설정하고 childList에서 Child 객체를 삭제하면 delete 쿼리가 나가는 것을 볼 수 있다.
Parent parent = em.find(Parent.class, parent.getId());
parent.getChildList().remove(0);
Hibernate:
/* delete hello.Child */
delete from Child where id=?
참고 : 어떤 이유인지는 모르겠지만 orphanRemoval = true 단독으로는 동작하지 않고 cascade = CascadeType.PERSIST 또는 ALL 옵션과 같이 사용해야 동작한다.
영속성 전이 + 고아 객체
- cascade = ALL과 orphanRemoval = true 옵션을 같이 사용하면 부모 엔티티를 통해서 자식 엔티티의 생명 주기를 관리할 수 있다.
- 자식 엔티티의 DAO 또는 Repository가 없어도 된다.
- 도메인 주도 설계(DDD)의 Aggregate Root 개념을 구현할 때 유용하다.
참고
'데이터베이스 > JPA' 카테고리의 다른 글
[JPA] 값 타입 컬렉션 : @ElementCollection, @CollectionTable (0) | 2021.03.24 |
---|---|
[JPA] @MappedSuperClass (0) | 2021.03.13 |
JPA JPQL 페치 조인(fetch join) (0) | 2021.02.21 |
JPA 임베디드 타입( Embedded Type, 복합 값 타입) : @Embedded, @Embeddable, @AttributeOverride, @AttributeOverrides (0) | 2021.02.20 |
JPA 지연로딩을 사용해야하는 이유, 지연로딩(Lazy)과 즉시로딩(Eager) (0) | 2021.02.12 |
댓글