나는 jpa 에서 @OneToMany(cascade = CascadeType.ALL)
처럼 cascade의 옵션을 무심코 쓴 경험이 있다. 알지도 못하고 사용한 나 자신에 대해서 반성하게 되며, cascade의 옵션에 대해서 이해한 내용을 정리해보겠다
cascade 는 영속성 전이에 활용하는 옵션이다. (매핑 정보와는 전혀 관련이 없다) 예시로 A 엔티티와 관계가 있는 B 엔티티를 함께 저장하고 싶다고 할때 cascade 를 활용하면 유용하다. 더 정확하게는, A 엔티티를 영속상태를 만들때 B 엔티티도 함께 영속 상태로 만드는 것이다. 아래 코드를 살펴보자.
@Entity
@Getter @Setter
public class Parent {
@Id
@GeneratedValue
@Column(name = "parent_id")
private Long id;
private String name;
@OneToMany(mappedBy = "parent", cascade = CascadeType.ALL)
private List<Child> ChildList = new ArrayList<>();
//편의 메서드
public void addChild(Child child) {
child.setParent(this);
ChildList.add(child);
}
}
@Entity
@Getter @Setter
public class Child {
@Id @GeneratedValue
@Column(name = "child_id")
private Long id;
private String name;
@ManyToOne
@JoinColumn(name = "parent_id")
private Parent parent;
}
부모 엔티티와 자식 엔티티는 일대다 관계에 있다.
이 상황에서 부모 엔티티를 저장할때 자식 엔티티도 함께 저장하고 싶다면, 부모 엔티티에 해당하는 @OneToMany
옵션에 cascade = CascadeType.ALL
을 지정해주면 된다.
//main.class
Child child1 = new Child();
child1.setName("c1");
Child child2 = new Child();
child2.setName("c2");
Parent parent = new Parent();
parent.setName("p1");
parent.addChild(child1);
parent.addChild(child2);
em.persist(parent);
위 코드에서는 분명 parent 엔티티만 저장했는데 실행 결과를 보면 Child가 함께 저장된다.
실행결과:
관련된 엔티티가 함께 저장된다는 것은 매우 편하지만, 이 속성을 남발해서는 안된다. 위의 예제에서는 부모 엔티티만 자식 엔티티를 관리하기 때문에 cascade all
옵션이 유용했다. 그런데 자식 엔티티를 부모 엔티티 뿐만 아니라 다른 곳에서도 관리하면 어떨까? 내가 부모 엔티티를 삭제하면 자식 엔티티도 함께 삭제되는 치명적인 문제가 발생한다. 그러면 자연스레 자식 엔티티를 참조하는 여러 엔티티에서 문제가 발생하는 것이다. 따라서 cascade
를 사용할 때 한곳에서만 관리될 때 해당 옵션을 사용할 수 있도록 하자.