반응형
JPA에서 연관된 객체들을 저장하거나 삭제할 때, 매번 em.persist() 또는 em.remove()를 수동으로 호출하는 건 매우 번거롭다.
이때 등장하는 개념이 영속성 전이(Cascade) 와 고아 객체 제거(orphanRemoval) 이다.
영속성 전이(Cascade)란?
연관된 엔티티도 자동으로 함께 영속성 상태로 관리하고 싶을 때 사용하는 기능입니다.
예를 들어, 게시글(Parent)과 댓글(Child)의 관계가 있다고 할 때, 게시글을 저장할 때 댓글도 자동으로 저장되길 원한다면 cascade가 필요합니다.
@Entity
public class Parent {
@Id @GeneratedValue
private Long id;
private String name;
@OneToMany(mappedBy = "parent", cascade = CascadeType.PERSIST) // 또는 ALL
private List<Child> childList = new ArrayList<>();
public void addChild(Child child) {
childList.add(child);
child.setParent(this);
}
}
@Entity
public class Child {
@Id @GeneratedValue
private Long id;
private String name;
@ManyToOne
@JoinColumn(name = "parent_id")
private Parent parent;
}
Child child1 = new Child();
Child child2 = new Child();
Parent parent = new Parent();
parent.addChild(child1);
parent.addChild(child2);
em.persist(parent); // ✅ child1, child2도 함께 persist됨
// cascade옵션을 쓰지 않았다면 child1, child2를 두번 persist해줘야함
언제 사용하는가?
- 연관된 엔티티의 생명주기를 부모가 전적으로 관리할 때
- 대표적인 예: 게시글 - 댓글, 주문 - 주문상품, 설문 - 질문 등 "소유 관계"
❗ 여러 주인이 존재하는 연관관계에서는 절대 사용하면 안 됨
→ ex. 여러 게시글이 하나의 댓글을 공유하는 경우 (잘못된 모델링이지만)
🎯 Cascade 옵션 종류
옵션 | 설명 |
ALL | 모든 Cascade 기능을 포함 |
PERSIST | 연관 객체도 persist() 자동 호출 |
MERGE | 병합 시 함께 병합 |
REMOVE | 삭제 시 함께 삭제 |
REFRESH | DB로부터 갱신할 때 함께 갱신 |
DETACH | 영속성 컨텍스트에서 분리할 때 함께 분리 |
🧹 고아 객체 제거 (orphanRemoval)
부모 객체에서 연관관계를 끊어버리면, JPA가 해당 자식 엔티티를 자동으로 DELETE 하는 기능
@OneToMany(mappedBy = "parent", cascade = CascadeType.ALL, orphanRemoval = true)
private List<Child> childList = new ArrayList<>();
Parent parent = em.find(Parent.class, 1L);
parent.getChildList().remove(0); // 해당 child 엔티티 DELETE 쿼리 발생
- JPA가 자동으로 DELETE FROM child WHERE id = ? 실행
- 연관관계가 끊어진 자식 엔티티를 고아(Orphan) 라고 판단하고 제거
언제 사용하는가?
- Cascade와 마찬가지로 참조하는곳이 하나일 때 사용
- @One ToOne, @OneToMany만 사용가능
Cascade vs OrphanRemoval 차이점
구분 | Cascade | OrphanRemoval |
역할 | 부모 저장/삭제 시 자식도 함께 처리 | 연관관계 끊긴 자식을 자동 삭제 |
대상 | persist, remove 등 엔티티 상태 변화 | 컬렉션에서 제거된 객체 |
필요 조건 | 연관관계 유지 | 참조가 제거됨 (null 또는 List.remove()) |
주의사항 | 생명주기 공유일 때만 사용 | 참조하는 곳이 하나일 때만 사용 |
CascadeType.ALL + orphanRemoval = true
이 둘을 함께 사용하면 아래와 같은 설계가 가능해집니다:
- parent.addChild(child) → 자동으로 저장
- parent.getChildList().remove(child) → 자동 삭제
- em.remove(parent) → 연관된 child도 자동 삭제
이 조합은 부모 엔티티를 통해 자식의 생명주기를 완벽하게 제어하는 것을 의미합니다.
반응형
'프로그래밍 > JPA' 카테고리의 다른 글
[JPA] 값 타입과 불변 객체 (2) | 2025.07.23 |
---|---|
[JPA] 값 타입 (1) | 2025.07.22 |
[JPA] 즉시 로딩과 지연 로딩 (2) | 2025.07.16 |
[JPA] 프록시와 연관관계 관리 (0) | 2025.07.15 |
[JPA] Mapped Superclass - 매핑 정보 상속 (0) | 2025.07.03 |