본 포스팅은 인프런 - 자바 ORM 표준 JPA 프로그래밍 (기본편) 을 강의를 바탕으로 공부하고 정리한 글입니다.
영속성 전이 (CASECADE)
- 특정 엔티티를 영속 상태로 만들 때 그와 연관된 엔티티도 함께 영속 상태로 만드는 기능이다.
- 예) 부모 엔티티 저장시 자식 엔티티도 함께 저장
- 영속성 전이는 연관관계를 매핑하는 것과 아무 관련 없다. 부모 엔티티를 영속화(persist)할 때, 자식 엔티티도 함께 영속화하는 편리함을 제공해주는 기능일 뿐이다.
부모 엔티티와 자식 엔티티를 저장하는 간단한 예제를 통해 확인해 보자.
👉🏻 영속성 전이 적용 전
@Entity
public class Parent {
...
@OneToMany(mappedBy = "parent")
private List<Child> childList = new ArrayList<>();
}
@Entity
public class Child {
...
@ManyToOne
@JoinColumn(name = "parent_id")
private Parent parent;
}
Parent parent = new Parent();
Child child1 = new Child();
Child child2 = new Child();
parent.addChild(child1);
parent.addChild(child2);
em.persist(parent); // 부모 저장
em.persist(child1); // 자식1 저장
em.persist(child2); // 자식2 저장
엔티티를 저장하기 위해 연관된 모든 엔티티가 영속상태여야 하므로, 부모 엔티티와 연관된 자식 엔티티를 각각 영속상태로 만들어줘야 한다.
이때 CASECADE 옵션을 사용해 이러한 번거로움을 덜 수 있다.
👉🏻 영속성 전이 적용 후
@Entity
public class Parent {
...
@OneToMany(mappedBy = "parent", cascade = CascadeType.ALL)
private List<Child> childList = new ArrayList<>();
}
Child child1 = new Child();
Child child2 = new Child();
Parent parent = new Parent();
parent.addChild(child1);
parent.addChild(child2);
em.persist(parent); // 영속성 전이를 적용해 parent를 저장할 때 child도 함께 저장
CasecadeType.ALL을 지정하면 부모 엔티티를 영속화할 때 자식 엔티티도 함께 영속화시켜준다.
CASECADE 종류
- ALL : 모두 적용
- PERSIST : 영속
- REMOVE : 삭제
- MERGE : 병합
- REFRESH : 새로고침
- DETACH : 분리
CASECADE 주의사항
무조건적으로 영속성 전이를 사용하는 것은 위험할 수 있다.
만약 하나의 자식 클래스를 여러 클래스에서 참조하고 있는 경우 영속성 전이를 사용하면 운영이 힘들어 질 수 있다.
따라서 다음과 같은 경우에 영속성 전이를 사용하자.
- Parent와 Child의 라이프 사이클이 동일할 때
- 특정 엔티티가 개인 소유할 때(Child가 하나의 Parent에 완전히 종속적)
고아 객체 (ORPHAN)
- JPA에서 부모 엔티티와 연관관계가 끊어진 자식 엔티티를 자동으로 삭제하는 고아 객체 제거 기능이다.
- orphanRemoval = true
고아 객체도 간단한 부모, 자식 엔티티를 삭제하는 예제를 통해 확인해보도록 하자.
@Entity
public class Parent {
...
@OneToMany(mappedBy = "parent", cascade = CascadeType.ALL, orphanRemoval = true)
private List<Child> childList = new ArrayList<>();
}
Child child1 = new Child();
Child child2 = new Child();
Parent parent = new Parent();
parent.addChild(child1);
parent.addChild(child2);
em.persist(parent);
em.flush();
em.clear();
Parent findParent = em.find(Parent.class, parent.getId());
findParent.getChildList().remove(0); // 자식 참조 제거
Hibernate:
/* delete hellojpa.Child */ delete
from
Child
where
child_id=?
참조가 제거된 엔티티는 다른 곳에서 참조하지 않는 고아 객체인 것으로 보고 삭제한다.
단, 참조하는 객체가 여러 개라면 문제가 발생 할 수 있기 때문에 @OneToOne, @OneToMany에서만 사용이 가능하다.
만약 부모를 제거하면 자식은 고아가 된다.
따라서 orpahRemoval 기능을 활성화 하면, 부모를 제거할 때 자식도 함께 제거가 된다.
이것은 CasecadeType.REMOVE를 설정한 것과 동일하게 동작한다.
영속성 전이 + 고아 객체, 생명주기
- cacade = CascadeType.ALL + orphanRemovel = true
- 스스로 생명주기를 관리하는 엔티티는 em.persist()로 영속화하며, em.remove()로 제거한다.
- 두 옵션을 모두 활성화 하면 부모 엔티티를 통해서 자식의 생명주기를 관리할 수 있다.
- 도메인 주도 설계(DDD)의 Aggregate Root개념을 구현할 때 유용하다.
'🌱 Spring > JPA' 카테고리의 다른 글
[JPA] JPQL : 페이징 (0) | 2022.11.03 |
---|---|
[JPA] JPQL : 기본 문법 (0) | 2022.10.29 |
[JPA] JPA가 지원하는 쿼리 방법 (JPQL, Criteria, QueryDsl) (0) | 2022.10.29 |
[JPA] 값 타입 (0) | 2022.10.19 |
[JPA] 즉시 로딩(LAZY)과 지연 로딩(EAGER) (0) | 2022.10.18 |
[JPA] 프록시 (0) | 2022.10.18 |
[JPA] 상속관계 매핑(@Inheritance), 매핑 정보 상속@MappedSuperclass) (0) | 2022.10.17 |
[JPA] 연관관계 매핑(3) - 다중성 (ManyToOne, ManyToOne, OneToOne, ManyToMany) (1) | 2022.10.11 |