예전에 만들던 프로젝트를 진행할 때 게시글을 업로드하고 지울 때 댓글과 사진에 대한 엔티티를 한번에 지우기위해 서비스에서 따로 로직을 추가했던 기억이 난다. 일일이 코드를 작성해야한다는것에 불편한점을 느꼈었는데, 이걸 해결해주는게 바로 Cascade
와 orphanRemoval
옵션이다! 유용함 👍
예를들어 내가 게시판이라는 엔티티를 구현할때 사용자
와 게시물
이라는 테이블이 있다고 가정해보자 이때 게시물
테이블은 사용자
테이블을 참조하는 FK(foreign key)
가 있을 수 있는데 일반적으로 사용자
테이블은 게시물
테이블와 부모-자식 관계를 띄어 삭제되면 해당 테이블에 관련된 게시물
테이블을 삭제하지 않는 한 오류가 발생할것이다.(=참조 무결성) 개발자는 이 오류를 위해 따로 FK와 관련된 테이블을 먼저 삭제하는 로직을 짜야하기때문에 번거로운 작업이라고 볼 수 있다. 때문에!! 이 연관관계 옵션은 이 고민 도와준다~
부모 엔티티에서 자식 엔티티로의 상태 변화를 전파시키는 옵션중 하나로 엔티티의 상태가 변화되었을 때 연관되어있는 엔티티(@OneToMany
, @ManyToOne
같은것들) 도 상태를 변화시키는 옵션이다.
적용할 수 있는 옵션은 다음과 같다.
@Entity
public class Parent {
@OneToMany(mappedBy = "parent", cascade = CascadeType.ALL)
private List<Child> children = new ArrayList<>();
// ...
}
Parent
와 Child
엔티티 간의 일대다 관계를 설정하고, CascadeType.ALL
옵션을 통해 부모 엔티티의 모든 변경이 자식 엔티티에도 전파되도록 설정한 예시. 만약 Parent
엔티티를 삭제하면? 연관된 Child
엔티티도 삭제됨
CascadeType.REMOVE
옵션과 비슷한 옵션으로는 orphanRemoval
이 있다. 이름만 봐서는 고아(...)를 제거하는 옵션인데 이것은 고아 엔티티를 말하는 것으로 부모 엔티티와 연관관계가 떨어진 자식 엔티티를 말한다 차이점은 CascadeType.REMOVE
은 부모 엔티티를 삭제할때 함께 삭제되는거지만 orphanRemoval
은 부모 엔티티와 연결이 끊어진경우 자식 엔티티를 삭제하는것이다!
따라서 두 옵션을 적절히 조합해서 쓴다면? 엔티티의 생명주기를 관리할 때 훨씬 편리해지겠죠?
@Entity
public class Order {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@OneToMany(mappedBy = "order", cascade = CascadeType.PERSIST, orphanRemoval = true)
private List<OrderItem> orderItems = new ArrayList<>();
}
@Entity
public class OrderItem {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@ManyToOne
private Order order;
}
위는 주문(Order)과 주문상품(OrderItem)에 관한 예시인데
CascadeType.PERSIST
옵션으로 인해 관련된 상품들도 저장됨orphanRemoval = true
옵션으로 인해 상품들이 자동으로 삭제됨처음에 어 이거완전 개꿀이다 ㅋㅋ 해놓고 옵션을 남발하다가는 게시물을 하나 지우니까 해당 사용자가 쓴 모든 댓글이 지워지는.. 일이 일어날수도있다 ㅋㅋ; 그중에서 특히 ALL 옵션은 너무나 포괄적이기때문에 사용을 권장하진 않을거같다는 생각 😅 언제나 늘 그렇듯 모든 상황은 절대적이 아니며 무조건적으로 나쁜것도 없다는 점~