[JPA] 영속성 전이 (CASCADE)

19·2022년 10월 17일
0

JPA

목록 보기
13/18
post-custom-banner

영속성 전이 (CASCADE)

특정 엔티티를 영속 상태로 만들 때, 연관된 엔티티도 함께 영속화하고 싶을 때 사용하는 옵션
ex) 부모 엔티티를 저장할 때, 자식 엔티티도 함께 저장

부모 엔티티)

@Entity
public class Parent {
    @Id
    @GeneratedValue
    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);
    }
}

자식 엔티티)

@Entity
public class Child {
    @Id
    @GeneratedValue
    private Long id;

    private String name;

    @ManyToOne
    @JoinColumn(name = "parent_id")
    private Parent parent;
}

CASCADE 옵션을 키지 않고, 엔티티를 저장할 때)

Parent parent = new Parent();

Child child1 = new Child();
Child child2 = new Child();

// 양방향 값 세팅
parent.addChild(child1);
parent.addChild(child2);

// 저장!
em.persist(parent);
em.persist(child1);
em.persist(child2);
  • parent, child 엔티티를 일일이 저장해주어야 한다는 번거로움이 있다
  • CASCADE 옵션으로 부모 엔티티를 저장할 때, 연관된 자식 엔티티도 함께 저장되도록 할 수 있다

부모 엔티티에서 cascade 옵션을 켜준다.

// CASCADE 옵션 설정
@OneToMany(mappedBy = "parent", cascade = CascadeType.ALL)
private List<Child> childList = new ArrayList<>();

부모 엔티티만 저장할 때, 연관된 자식 엔티티도 함께 저장된다.

Parent parent = new Parent();

Child child1 = new Child();
Child child2 = new Child();

// 양방향 값 세팅
parent.addChild(child1);
parent.addChild(child2);

// 저장!
// parent 중심 개발 시, parent를 persist하면 관련된 child들이 함께 persist 되도록 하고 싶다. -> CASCADE 옵션을 사용한다.
em.persist(parent);

// CASCADE 속성을 설정하면 하나씩 persist안해도 됨
//em.persist(child1);
//em.persist(child2);

  • 부모 엔티티만 persist했는 데, 자식 엔티티도 함께 저장된다.

  • parent만 persist했음에도, 영속성 전이가 일어나 연관된 하위 엔티티에 전파가 된다.

종류

ALL: 모두 적용
PERSIST: 영속
REMOVE: 삭제
MERGE: 병합
REFRESH: REFRESH
DETACH: DETACH


주의할 점

아무 곳에나 남발하면 큰일난다.
운영과 관리가 안되기 때문에, 단일 엔티티에 종속적일 때만 사용한다.

ex) Child는 Parent에만 종속되어 있기 때문에, CASCADE 옵션 사용에 문제가 없다
BUT, Parent뿐만 아니라 Member에도 종속되어 있다면?
-> CASCADE 옵션 사용 X, 따로따로 관리


언제 / 어디에 사용해야 하는지?

단일 엔티티에 종속적일 때만 사용하며, 양방향 매핑 시, @OneToMany, @OneToOne이 걸린 컬럼에 사용한다.

예를 들어, Post, Image 엔티티가 있고, 1:N의 관계, 양방향이며, Image가 Post에만 종속적일 때 사용할 수 있는 것이다.

Image에 Post의 외래키가 있을 것이고, 양방향이기 때문에 Post에는 List<Image> images가 있을 것이다.

@OneToMany(mappedBy = "post")
List<Image> images = new ArrayList<>();

이 때, images에 cascade옵션을 사용하면 된다.

@OneToMany(mappedBy = "post", cascade = CascadeType.ALL)
List<Image> images = new ArrayList<>();

Post가 삭제될 때, images도 함께 삭제된다.

CASCADE 참고


고아 객체

고아는 부모 엔티티와 연관관계가 끊어진 자식 엔티티를 의미한다.
orphanRemoval = true 옵션을 통해 고아가 된 객체를 자동으로 삭제할 수 있다.


부모 엔티티에서 CASCADE 옵션과 고아 객체를 자동 삭제하는 옵션을 켜준다.

@OneToMany(mappedBy = "parent", cascade = CascadeType.ALL, orphanRemoval = true)
private List<Child> childList = new ArrayList<>();

고아 객체를 의도적으로 만들어본다.

// findParent의 childList에는 2개의 child객체가 있다. (위 참조)
Parent findParent = em.find(Parent.class, parent.getId());
findParent.getChildList().remove(0);

  • parent의 childList에서 의도적으로 child 객체 1개를 뺐고, 이로 인해 해당 child 객체는 고아가 되었다.
    • 부모 엔티티와 연관관계가 끊어짐
    • 'orphanRemoval = true'로 인해 자동으로 삭제 쿼리가 나간다.

CASCADE 옵션없이 'orphanRemoval = true' 옵션만 켜두면, CascadeType.REMOVE처럼 동작한다

@OneToMany(mappedBy = "parent", orphanRemoval = true)
private List<Child> childList = new ArrayList<>();

Parent findParent = em.find(Parent.class, parent.getId());
em.remove(findParent);

  • 부모 엔티티인 parent를 삭제하니까 연관된 자식 엔티티들이 삭제된다.

주의할 점

CASCADE와 마찬가지로, 단일 엔티티에 종속적일 때만 사용해야 한다.
@OneToOne, @OneToMany만 가능


영속성 전이 + 고아 객체

CascadeType.ALL + orphanRemoval = ture
두 옵션을 모두 활성화하면 부모 엔티티를 통해서 자식의 생명주기를 관리할 수 있다.



참고

자바 ORM 표준 JPA 프로그래밍 - 기본편 - 김영한

profile
하나씩 차근차근
post-custom-banner

0개의 댓글