JPA

[JPA] 16. 영속성 전이(CASCADE)

inuma 2021. 1. 18. 23:16
프로젝트 git url github.com/rtef23/JpaStudy
필요 1. docker
2. docker-compose
프로젝트 정보 mysql : 5.7 - docker image
java : 1.8

 

영속성 전이(CASCADE)

  • 특정 엔티티를 영속 상태로 만들 때, 연관된 엔티티도 함께 영속 상태로 만드는 것
    • 부모 엔티티를 저장할 때, 자식 엔티티도 함께 저장하는 것
@Entity
public class Parent {
  @Id @GeneratedValue private Long id;

  private String name;

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

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

  private String name;

  @ManyToOne
  @JoinColumn(name = "children")
  private Parent parent;
  
  ...
}
Child child1 = new Child();
child1.setName("child-1");

Child child2 = new Child();
child2.setName("child-2");

Parent parent = new Parent();
parent.setName("parent-1");

parent.addChild(child1);
parent.addChild(child2);

entityManager.persist(parent);

  • parent만 저장(persist)하는데 연관된 child들도 같이 저장되게 된다.
  • 연관된 엔티티가 다른 엔티티와 연관관계가 있는 경우, CASCADE를 쓰는 것은 운영을 복잡하게 만들 수 있다.(종속적인 경우에만 사용하는 것을 추천)

 

CASCADE 종류

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

 

고아 객체

  • 부모 엔티티와 연관관계가 끊어진 자식 엔티티를 자동으로 삭제
  • orphanRemoval = true
@Entity
public class Parent {
  @Id @GeneratedValue private Long id;

  private String name;

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

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

  private String name;

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

 

  • 별도의 remove api를 사용하지 않았지만 Parent - Children 컬렉션 0번에 있던 엔티티를 제거하는 쿼리가 실행되었다.(부모 엔티티와 연관 관계가 끊어졌기 때문에)
Parent findParent1 = entityManager.find(Parent.class, parent.getId());
findParent1.getChildren().remove(0);

 

  • 부모 객체가 지워지는 경우에도 하위 자식을 제거하는 쿼리가 전송되게 된다.
    • 부모 id로 Child delete 쿼리를 실행하면 1번만 수행하게 될 듯 하지만 개별 Child의 id로 삭제 쿼리가 전송되게 된다.
  • CascadeType.REMOVE와 같이 동작하게 된다.

 

Parent findParent1 = entityManager.find(Parent.class, parent.getId());
entityManager.remove(findParent1);

주의할 점

  • 특정 엔티티가 개인 소유할 때 사용
  • @OneToOne, @OneToMany에서만 사용 가능

 

영속성 전이 + 고아 객체, 생명 주기

  • 두 옵션을 모두 활성화하면 부모 엔티티를 통해서 자식의 생명주기를 관리할 수 있음
  • DDD에서 Aggregate root 개념을 구현할 때 유용