ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 스프링 : CascadeType.ALL 사용해보기
    백엔드 : 서버공부/Spring 2024. 2. 11. 23:38
    728x90

    스프링을 공부하고 프로젝트를 진행하면서 JPA를 사용하게됬는데 이때 연관된 엔티티들을 데이터베이스에 저장, 수정 또는 삭제할 때, 이러한 작업들을 각각 수행해야 하는 번거로움이 있었습니다.(번거로움 + 수작업 누락으로인한 오류발생)
    예를 들어, 하나의 주문(Order)이 여러 주문 항목(OrderItem)과 하나의 배송 정보(Delivery)를 포함하는 상황을 생각해보면,
    주문을 데이터베이스에 저장할 때, 주문 뿐만 아니라 모든 주문 항목과 배송 정보도 함께 저장해야 합니다.
    이 과정이 수동으로 진행된다면, 코드는 불필요하게 복잡해지고, 데이터 일관성을 유지하는 것이 어려워집니다.
     
    이러한 문제의 해결책으로  `CascadeType.ALL` 이 있다는 것을 알게되었습니다.
     
    JPA에서 CascadeType.ALL을 사용하는 것은 연관된 엔티티들에 대한 영속성(Persistence) 관리를 부모 엔티티가 직접 책임지겠다는 의미입니다. (그러니까 부모 엔티티가 자식 엔티티의 생성,삭제등의 작업을 한번에 하겠다라는 의미입니다.)
    즉 부모 엔티티를 저장, 수정, 삭제할 때 연관된 자식 엔티티들도 같은 작업이 자동으로 적용되도록 해주는 것입니다.
     
    예시를 들어 보겠습니다.
    주문(Order)이라는 행위는 여러 개의 주문 항목(OrderItem)과 배송 정보(Delivery)를 포함합니다.
    이 세 개의 엔티티는 서로 밀접하게 연관되어 있습니다.

    연관관계를 대략 그려보면 이렇습니다.

    • 주문(Order): 주문 정보를 나타냅니다.
    • 주문 항목(OrderItem): 주문된 각 상품의 정보(예: 상품, 수량, 가격)를 나타내고, 하나의 주문에는 여러개의 주문 상품이 있습니다.
    • 배송 정보(Delivery): 배송받을 주소, 배송 상태 등을 나타냅니다. 주문하나당 하나의 배송 상태가 있습니다.

    이런 상황에서 CascadeType.ALL 없이 주문을 생성하고 데이터베이스에 저장하는 기능을 구현해보면 아래와 같습니다.

    CascadeType.ALL을 적용하지 않음

    Delivery delivery = new Delivery(); 
    OrderItem orderItemA = new OrderItem(); 
    OrderItem orderItemB = new OrderItem(); 
    
    // 주문 생성
    Order order = Order.createOrder(delivery, orderItemA, orderItemB);
    
    // CascadeType.ALL이 적용되지 않았으므로, 각 엔티티를 개별적으로 저장
    entityManager.persist(delivery); // 배송 정보 저장
    entityManager.persist(orderItemA); // 주문 항목 A 저장
    entityManager.persist(orderItemB); // 주문 항목 B 저장
    entityManager.persist(order); // 마지막으로 주문 저장

     
    코드가 길고 복잡한것을 확인할 수 있습니다. 
    이때 CascadeType.ALL을 적용하면 아래와 같이 코드가 줄어듭니다.

    CascadeType.ALL 적용

    Delivery delivery = new Delivery(); // 배송 정보 설정
    OrderItem orderItemA = new OrderItem(); // 주문 항목 A 설정
    OrderItem orderItemB = new OrderItem(); // 주문 항목 B 설정
    
    Order order = Order.createOrder(delivery, orderItemA, orderItemB);
    
    // CascadeType.ALL이 적용되어 있으므로, Order를 저장할 때 연관된 모든 엔티티가 자동으로 저장
    // 이 한 줄이면 order, delivery, orderItemA, orderItemB가 모두 저장
    entityManager.persist(order);

     
     
    cascadeType.ALL을 어떻게 적용하는지 보면은 아래와 같습니다.

    @Entity
    @Table(name = "orders")
    @Getter 
    @Setter
    @NoArgsConstructor(access = AccessLevel.PROTECTED)
    public class Order {
    
        @Id @GeneratedValue
        @Column(name = "order_id")
        private Long id;
    
        @JsonIgnore
        @OneToMany(mappedBy = "order", cascade = CascadeType.ALL)
        private List<OrderItem> orderItems = new ArrayList<>();
    
        @JsonIgnore
        @OneToOne(fetch = LAZY, cascade = CascadeType.ALL)
        @JoinColumn(name = "delivery_id")
        private Delivery delivery;
    
        }

     

    하지만 단점이 있어서 실무에서는 권장되지 않는다고 합니다. CascadeType.ALL을 사용하면 데이터베이스 작업이 많아져 성능에 영향을 줄 수 있기 때문입니다. 특히 많은 양의 데이터가 있는 경우에는 이러한 영향이 더욱 커질 수 있습니다.

     

     

     

    결론 : cascadeType.ALL을 통해 코드를 한번 줄여보자

Designed by Tistory.