영속성 전이(Cascade)

이유진·2024년 10월 6일
0

스프링 이론 다지기

목록 보기
10/12
post-thumbnail

영속성 전이(Cascade)

🌱Cascade 등장 배경

@Setter
@Getter
@Entity
public class Parent {
    @Id
    @GeneratedValue
    private Long id;

    private String name;

    @OneToMany(mappedBy = "parent")
    private List<Child> childes = new ArrayList<>();

    public void addchild(Child child) {
        childes.add(child);
        child.setParent(this);
    }
}
@Setter
@Getter
@Entity
public class Child {
    @Id
    @GeneratedValue
    private Long id;

    private String name;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "parent_id")
    private Parent parent;

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

    Parent parent = new Parent();
    parent.addchild(child1);
    parent.addchild(child2);

    em.persist(parent);
    em.persist(child1);
    em.persist(child2);
  • 현재 Parent와 Child는 1:N 양방향 연관관계로 맺어진 상황이다. 여기서 3가지 인스턴스를 모두 영속화 시키기 위해서는 em.persist를 3번 호출해서 영속화해야한다.

  • JPA에서는 이를 간편하게 처리할 수 있는 방법으로 영속성 전이(CASCADE)의 PERSIST 옵션을 제공한다.


🌱영속성 전이란?

  • 영속성 전이

    • 영속 상태의 Entity에서 수행되는 작업들이 연관된 Entity까지 전파되는 상황을 뜻한다.
    • 영속성 전이를 적용하여 해당 Entity를 저장할 때 연관된 Entity까지 자동으로 저장하기 위해서는 자동으로 저장하려고 하는 연관된 Entity에 추가한 연관관계 애너테이션에 CASCADE의 PERSIST 옵션을 설정하면된다.
    • 아래와 같이 어노테이션에 영속성 전이를 적용해준다.
    @OneToMany(mappedBy = "parent",cascade = CascadeType.PERSIST)
        private List<Child> childes = new ArrayList<>();
    	Child child1 = new Child();
    	Child child2 = new Child();
    
        Parent parent = new Parent();
        parent.addchild(child1);
        parent.addchild(child2);
    
        em.persist(parent);
  • 예제

    @Entity
    @Getter
    @Setter
    @Table(name = "users")
    public class User {
        @Id
        @GeneratedValue(strategy = GenerationType.IDENTITY)
        private Long id;
        private String name;
    
        @OneToMany(mappedBy = "user", cascade = {CascadeType.PERSIST, CascadeType.REMOVE})
        private List<Food> foodList = new ArrayList<>();
    
        public void addFoodList(Food food) {
            this.foodList.add(food);
            food.setUser(this);// 외래 키(연관 관계) 설정
        }
    }
    @Test
    @Transactional
    @Rollback(value = false)
    @DisplayName("영속성 전이 삭제")
    void test4() {
        // 고객 Robbie 를 조회합니다.
        User user = userRepository.findByName("Robbie");
        System.out.println("user.getName() = " + user.getName());
    
        // Robbie 가 주문한 음식 조회
        for (Food food : user.getFoodList()) {
            System.out.println("food.getName() = " + food.getName());
        }
    
        // Robbie 탈퇴
        userRepository.delete(user);
    }
    • 고객 Entity의 @OneToMany 애너테이션에 연관된 음식 Entity도 자동으로 삭제될 수 있도록 REMOVE 옵션을 추가한다.

    • Robbie 고객 Entity 객체를 조회한 후 해당 객체를 delete 하자 자동으로 연관된 음식 데이터들이 삭제된다.


🌱Cascade 종류

  • CascadeType.ALL : 모든 Cascade 옵션을 적용한다.
  • CascadeType.PERSIST : 엔티티를 영속화할 때, 연관된 엔티티도 함께 영속화한다.
  • CascadeType.REMOVE : 엔티티를 제거할 때, 연관된 엔티티도 함께 제거한다.
  • CascadeType.MERGE : 엔티티 상태를 병합할 때, 연관된 엔티티도 함께 병합한다.
  • CascadeType.REFRESH : 부모 엔티티를 Refresh하면, 연관된 엔티티도 함께 Refresh된다.
  • CascadeType.DETACH : 부모 엔티티를 Detach하면, 연관된 엔티티도 함께 Detach된다.

🌱Cascade를 어디에 사용할까?

  • 1:N 연관관계 기준으로 연관관계 주인이 항상 N쪽에 존재한다고 알고 있을텐데 이의 반대쪽 엔티티에 사용하면 된다.
  • 즉, 보통 @OneToMany가 걸린 엔티티에 Cascade를 걸어주면된다.

🌱고아 Entity 삭제

  • 이번에는 Cascade와 비슷한 orphanRemoval 옵션에 대해서 알아보자. 이 또한 마찬가지로 OneToMany나 OneToOne에 사용가능하다.
  • 부모와 연관관계가 끊어진 엔티티를 고아객체라하며 이러한 고아객체를 자동으로 삭제해주는 옵션을 활성화 시키는것이 orphanRemoval=true옵션을 @ OnetoMany에 걸어주면 되는 것이다.
@Entity
@Getter
@Setter
@Table(name = "users")
public class User {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String name;

    @OneToMany(mappedBy = "user", cascade = CascadeType.PERSIST, orphanRemoval = true)
    private List<Food> foodList = new ArrayList<>();

    public void addFoodList(Food food) {
        this.foodList.add(food);
        food.setUser(this);// 외래 키(연관 관계) 설정
    }
}

🌱orphanRemoval=true와 Cascade.REMOVE 차이

처음 둘의 개념을 접했을때 차이를 구분할 수 없었다.

  • Cascade.REMOVE의 경우 1에 해당하는 엔티티를 em.remove를 통해 직접 삭제할 때,그 아래에 있는 N에 해당하는 엔티티들이 삭제되는 것이다.
  • orphanRemoval=true는 위의 경우는 물론,엔티티의 리스트에서 요소를 삭제하기만 해도 해당 엔티티가 delete되는 기능까지 포함하고 있다고 이해하면 된다.
  • orphanRemoval=true와 Cascade.ALL을 함께 쓰면 부모-자식 관계에서 자식의 생명 주기를 완전히 부모에 의존하게 만들 수 있다.
    • 자식이 부모로부터 제거될 때 자동으로 삭제되며, 부모 엔티티의 모든 작업(저장, 삭제 등)이 자식에게도 전파됩니다.(부모를 통해 자식의 생명주기 관리가 가능하다는 의미)

참고

https://hongchangsub.com/jpa-cascade-2/

https://velog.io/@chiyongs/JPA-%EC%98%81%EC%86%8D%EC%84%B1-%EC%A0%84%EC%9D%B4-CASCADE

profile
🙌중요한건 꺾였는데도 그냥 하는 마음

0개의 댓글