반응형
본 내용은 온라인 강의 사이트 인프런의 김영한 님의 강의 내용이 포함되어 있습니다.
'자바 ORM 표준 JPA 프로그래밍 - 기본편'
영속성 전이(CASCADE)
특정 엔티티를 영속 상태로 만들 때, 연관된 엔티티도 함께 영속 상태로 만들고 싶으면 영속성 전이 기능을 사용한다.
JPA는 CASCADE 옵션으로 영속성 전이를 제공한다.
- 영속성 전이를 사용하면 부모 엔티티를 저장할 때 자식 엔티티도 함께 저장할 수 있다.
- 한 부모는 여러 명의 아이를 가질 수 있다.
- 여러 명의 자식은 한 부모를 가질 수 있다.
Parent
@Entity
public class Parent {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
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);
}
// Getter
// Setter
}
Child
@Entity
public class Child {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long Id;
private String name;
@ManyToOne
@JoinColumn(name = "PARENT_ID")
private Parent parent;
// Getter
// Setter
}
영속성 전이를 사용하지 않는 경우
Child child1 = new Child();
Child child2 = new Child();
Parent parent = new Parent();
parent.addChild(child1);
parent.addChild(child2);
// 모두 persist 해야함
em.persist(parent);
em.persist(child1);
em.persist(child2);
영속성 전이를 사용하는 경우
Parent
@Entity
public class Parent {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
@OneToMany(mappedBy = "parent", cascade = CascadeType.ALL)
private List<Child> childList = new ArrayList<>();
public void addChild(Child child) {
childList.add(child);
child.setParent(this);
}
// Getter
// Setter
}
Child child1 = new Child();
Child child2 = new Child();
Parent parent = new Parent();
parent.addChild(child1);
parent.addChild(child2);
em.persist(parent);
- Parent와 연관된 엔티티도 모두 persist()
영속성 전이 주의 사항
- 영속성 전이는 연관관계를 매핑하는 것과 아무 관련이 없다.
- 엔티티를 영속화할 때 연관된 엔티티도 함께 영속화하는 편리함을 제공하는 것뿐이다.
- 소유자가 1개일 때에는 사용할 수 있다
- 위 예시의 경우 Child의 소유자는 Parent 1개
- 만약, 소유자가 2개 이상일 경우 영속성 전이를 사용하면 안 된다.
- Member나 Team 등 Parent 외의 엔티티가 Child를 알고 있는 경우
CASCADE의 종류
- ALL : 모두 적용
- PERSIST : 영속
- REMOVE : 삭제
- MERGE : 병합
- REFRESH : REFRESH
- DETACH : DETACH
고아 객체
JPA는 부모 엔티티와 연관관계가 끊어진 자식 엔티티를 자동으로 삭제하는 기능을 제공하는데, 이를 고아 객체(ORPHAN) 제거라 한다.
고아 객체 제거
- 부모 엔티티의 컬렉션에서 자식 엔티티의 참조만 제거하면 자식 엔티티가 자동으로 삭제
- orphanRemoval = true
Parent
@Entity
public class Parent {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
@OneToMany(mappedBy = "parent", orphanRemoval = true)
private List<Child> childList = new ArrayList<>();
public void addChild(Child child) {
childList.add(child);
child.setParent(this);
}
// Getter
// Setter
}
Parent parent1 = em.find(Parent.class, id);
parent1.getChildren().remove(0); // 자식 엔티티를 컬렉션에서 제거
// DELETE SQL 쿼리 발생
DELETE FROM CHILD WHERE ID = ?
고아 객체 주의 사항
- 참조가 제거된 엔티티는 다른 곳에서 참조하지 않는 고아 객체로 보고 삭제하는 기능
- 참조하는 곳이 하나일 때만 사용해야 한다.
- 특정 엔티티가 개인 소유할 때 사용
- @OneToOne, @OneToMany만 사용 가능
참고
개념적으로 부모를 제거하면 자식은 고아가 된다.
- 고아 객체 제거 기능을 활성화하면, 부모를 제거할 때 자식도 함께 제거된다.
- cascade = CascadeType.REMOVE와 같은 동작을 한다.
// Parent cascade = CascadeType.ALL or CascadeType.REMOVE
@OneToMany(mappedBy = "parent", cascade = CascadeType.ALL)
private List<Child> childList = new ArrayList<>();
// Parent : orphanRemoval = true
@OneToMany(mappedBy = "parent", orphanRemoval = true)
private List<Child> childList = new ArrayList<>();
Parent findParent = em.find(Parent.class, parent.getId());
em.remove(findParent);
- Parent cascade = CascadeType.ALL or CascadeType.REMOVE
- 부모를 지우면 자식들도 모두 함께 제거된다.
- Parent : orphanRemoval = true
- 부모를 지우면 자식들도 모두 함께 제거된다.
영속성 전이 + 고아 객체, 생명주기
- cascade = CascadeType.ALL + orphanRemoval = true
- 일반적으로 엔티티는 em.persist()로 영속화, em.remove()로 제거한다.
- 엔티티 스스로 생명주기를 관리한다는 의미
- 두 옵션을 모두 활성화하면 부모 엔티티를 통해서 자식의 생명주기를 관리할 수 있다.
- 자식을 저장하려면 부모에서 등록하기만 해도 된다.(CASCADE)
- 자식을 삭제하려면 부모에서 삭제하기만 해도 된다.(orphanRemovel)
@Entity
public class Parent {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
@OneToMany(mappedBy = "parent", cascade = CascadeType.ALL, orphanRemoval = true)
private List<Child> childList = new ArrayList<>();
public void addChild(Child child) {
childList.add(child);
child.setParent(this);
}
// Getter
// Setter
}
자식을 저장하려면 부모에서 등록하기만 해도 된다.(CASCADE)
Child child1 = new Child();
Child child2 = new Child();
Parent parent = new Parent();
parent.addChild(child1);
parent.addChild(child2);
em.persist(parent);
자식을 삭제하려면 부모에서 삭제하기만 해도 된다.(orphanRemovel)
Parent findParent = em.find(Parent.class, parent.getId());
findParent.getChildList().remove(0);
em.remove(findParent);
참고
영속성 전이 + 고아 객체 옵션을 모두 사용할 경우
- 부모 엔티티를 통해서 자식의 생명주기를 관리할 수 있다.
- 도메인 주도 설계(DDD)의 애그리거트 루트(Aggregate Root) 개념을 구현할 때 유용하다.
반응형
'프레임워크(Framework) > JPA' 카테고리의 다른 글
[JPA] 값 타입과 불변 객체 - 값 타입 (2) (0) | 2022.12.09 |
---|---|
[JPA] 기본값 타입과 임베디드 타입 - 값 타입 (1) (0) | 2022.12.08 |
[JPA] 프록시와 연관관계 관리(지연 로딩과 즉시 로딩) (0) | 2022.12.06 |
[JPA] 고급 매핑(상속관계 매핑) - 엔티티 매핑(Entity Mapping) - 7 (0) | 2022.12.05 |
[JPA] 다양한 연관관계 매핑 - 엔티티 매핑(Entity Mapping) - 6 (0) | 2022.12.04 |