[SPRING] CascadeType 구분해서 사용하기

림민지·2025년 5월 15일

Today I Learn

목록 보기
57/62

JPA의 CascadeType.ALLCascadeType.PERSIST는 둘 다 영속성 전파(cascade persist)를 포함하고 있지만, 용도와 상황에 따라 구분해서 사용해야한다!

이 둘이 헷갈려서 글을 남기면서 이해하려고 한다ㅠㅠ

💡 공통점 : 둘 다 부모 엔티티.persist() 시 연관된 자식 엔티티도 자동으로 persist 된다

ALL로 설정하면 편한데 왜 구분해서 사용해야할까?

요약! : "명확한 책임 분리""예측 가능한 동작" 때문


📝 Cascade는 필요한 만큼만 사용하는 게 원칙이다

CascadeType.ALLpersist, merge, remove, refresh, detach를 모두 포함한다.

이걸 사용하면 생명주기 전체를 부모가 관리하게 되는데,,
생각보다 객체 관계는 항상 그렇게 강결합되지 않는다!

❗ "모든 생명주기를 위임해야 할 만큼 부모-자식 관계가 강해??"
→ 그게 아니라면, ALL은 너무 투머치임

🏆 PERSIST는 명확하고 안전한 책임 전파

CascadeType.PERSIST로 설정하게 되면

부모를 persist()할 때 자식도 자동으로 저장되지만

자식은 삭제, 병합, 갱신 등의 책임을 부모에게 묻지 않음 ❌


"저장할 땐 편하게, 나머지는 명시적으로!"

→ 유지보수 관점에서 매우매우 유리하다.

만약 REMOVE가 자동으로 전파되면...??

@Entity
public class Order {
    @OneToMany(mappedBy = "order", cascade = CascadeType.ALL)
    private List<OrderItem> items;
}

이렇게 부모:order / 자식 : item일때
누가 orderRepository.delete(order)만 호출하면????

👉 OrderItem도 모두 삭제된다....

사용자의 의도는 주문만 삭제하는건데, 의도치않은 오더아이템까지 싹 삭제가되는것 ]ㅠㅠ
이때 다른 엔티티가 이 오더아이템을 참조하고 있지 않다면 그나마 다행이지만..

다른 곳에서도 이 OrderItem을 참조하고 있었다면?😱
→ 참조 무결성 와장창... + 널포인터 에러까지

➡️ REMOVE는 되도록 명시적으로 delete 하는게 좋다

🤝 팀프로젝트에서의 이점

대형 프로젝트에서 팀원 간 예측 가능한 코드 유지가 가능하다!
persist만 전파되면 다른 팀원들이 “이건 저장만 자동이고 나머진 내가 책임져야 하는구나”라고 인식할 수 있기 때문~!

ALL은 어디까지 영향이 갈지 추적하기 어렵고,, 디버깅도 불편해진다!

👍 장점 정리

이유설명
책임 분리저장만 위임하고 나머지는 명시적으로 관리 가능
예측 가능성"부모 삭제 시 자식 삭제" 같은 예상치 못한 부작용 방지
유지보수성동작이 명확하므로 디버깅/리팩토링이 쉬움
안전성실수로 중요한 데이터를 삭제하거나 병합하는 일 방지

🎯 ALL은 언제 쓰면 될까?

진짜 부모-자식 생명주기가 완전!! 동일한 경우에 쓴다

단, 이때도 되도록 orphanRemoval = true를 함께 써야 일관성을 유지할 수 있다

+ 언제 orphanRemoval = true를 써야 할까?

부모-자식이 “소유/종속” 관계일 때!
→ 자식이 오직 하나의 부모에만 종속
→ 부모가 자식을 관리 & 자식이 부모 없이는 존재할 수 없을 때

연관관계를 끊으면 자식은 orphan(고아)이므로 자동 삭제해야 맞다!
→ 이때 orphanRemoval = true를 사용하는 것이다~

📌 CascadeType.PERSIST + orphanRemoval = true 조합

@OneToMany(mappedBy = "todo", cascade = CascadeType.PERSIST, orphanRemoval = true)
private List<Manager> managers = new ArrayList<>();

이 코드를 보자
Todo를 persist()하면 Manager도 자동 저장된다

todo.getManagers().remove(m) 하면, 해당 Manager는 DB에서도 삭제된다

➡️ 저장은 편하게 자동(persist)
➡️ 삭제는 명확하게 연관관계 변경으로 처리
➡️ 명시적 entityManager.remove() 없이도 정합성 유지

만약 반대로 orphanRemoval = false면?

remove() 해도 자식 엔티티는 DB에 남아 있음
→ 직접 entityManager.remove(manager) 호출해야 함,,,,
➡️ 삭제 누락 가능성, 정합성 문제 발생 위험 ↑

profile
@lim_128

0개의 댓글