콘텐츠로 이동

2021 08 17

2021-08-17

Cascade

  • 제약조건? - 결점 없이 정확하고 유효한 데이터가 데이터베이스에 저장될 수 있도록 하기 위하여 - 제약조건을 건다 == 사용자가 원하는 데이터만 걸러내도록 조건을 만드는 것 - NOT NULL - UNIQUE - PK - FK - CHECK: 기본연산자/비교연산자 등을 통해 조건 확인
  • DB에서 Cascade? - 참조 무결성이 깨지는 것을 허용하면서 관련된 모든 값을 업데이트하거나 삭제! - 참조 무결성이 깨지지 않도록 자동으로 값 생성하거나, 삭제하도록 도와줌 - CASCADE 옵션은 부모 테이블과 자식 테이블 간에 참조 설정 - 제약 조건을 활용하여 부모 테이블의 데이터가 삭제/변경 시 오류가 아닌 자식 테이블인 comments 테이블의 데이터에도 적용 - ON DELETE CASCADE - ON UPDATE CASCADE - 다른 테이블과 PK또는 FK로서의 관계가 여전히 존재한다면, PK가 존재하는 테이블을 맘대로 제거/비활성화 할 수 없다 - 부모 테이블 ~ 자식 테이블간의 참조 설정이 있다면, 부모 제약 조건 비활성화 & 이를 참조중인 자식 테이블 제약 조건 비활성화 하기 위함
  • JPA에서 Cascade? - Cascade 옵션: "엔티티의 상태" 변화를 전파시키는 옵션 - OneToMany, ManyToOne으로 양방향 관계를 맺는 엔티티의 상태 변화 전이에 사용 - "엔티티의 상태" 1. Transient: 객체 생성하고, 값 줘도 JPA나 hibernate가 그 객체 암것도 모르는 상태 2. Persistent: 저장 하고나서 JPA가 관리하는 상태 3. Detached: JPA가 더 이상 관리 X 4. Removed: JPA가 관리하긴 하는데, 실제 commit 일어날떄 삭제됨 - CascadeType - ALL: 상위 엔티티에서 하위 엔티티로 모든 작업을 전파 - PERSIST: 하위 엔티티까지 영속성 전달 (부모 저장시 자식도 저장) - MERGE: 하위 엔티티까지 병합 작업 지속 (업데이트? ON UPDATE CASCADE 인가?) - REMOVE: 하위 엔티티까지 제거 작업 지속 (ON DELETE CASCADE 인듯) - REFRESH: DB로 부터 인스턴스 값을 다시 읽어오기 - DETACH: 영속성 컨텍스트에서 엔티티 제거
  • CascadeType.PERSIST - flush가 발생할 때 CascadeType.PERSIST가 있다면 자식에 연쇄적으로 persist operation 발생 - persist operation
    - 만약 X가 새로운 엔티티라면, flush operation의 결과로 X는 데이터베이스에 트랜잭션 커밋 시점에 들어간다.
    - 만약 X가 이미 존재하는 엔티티라면, persist operation에서 무시된다.
    

    - 예상치 못한 동작 1

    class Member{
        // ...
    
        @OneToMany(mappedBy = "member", cascade = CascadeType.PERSIST)
        private List<Order> orderList = new ArrayList<>();
    }
    class Order{
        // ...
    
        @ManyToOne
        @JoinColumn(name = "member_id")
        private Member member;
    }
    
    public void deleteTest(){
        Member member = em.find(Member.class, 1);
    
        List<Order> orderList = member.getOrderLsit();
    
        for(Order order : orderList){
            em.remove(order);
        }
    }
    

      - 이 경우 flush시에 orderList에 남아있는 모든 order에 대해 persist 연산을 수행
          - delete 메서드가 안날라감
      - 따라서 CascadeType.PERSIST를 사용하려면, 삭제하려는 order에 맞춰 orderList에서 요소 삭제하거나
      - orphanRemoval = true를 줘서 삭제시 자동 delete 되게 해야함
    

    - 예상치 못한 동작 2 java @Entity class Member{ // ... @OneToMany(mappedBy = "member", cascade = CascadeType.ALL, orphanRemoval = true) private List<Order> orders; } @Entity class Item{ // ... @OneToMany(mappedBy = "item", cascade = CascadeType.ALL, orphanRemoval = true) private List<Order> orders; } @Entity class Order{ // ... @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "member_id") private Member member; @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(nane = "item_id") private Item item; } Member member = em.find(Member.class, 1); List<Order> orders = member.getOrders(); for(Order order : orders){ Integer size = order.getItem().getOrders().size(); // ... } member.getOrders().clear(); // expecting delete operation

      - 영속성 컨텍스트에 item의 order 요소들이 올라감
          - member의 orders를 비워 delete 연산을 수행하려해도, item의 orders 요소들이 남아있어 PERSIST 연산 수행됨
              - delete 씹힘!
    
  • CascadeType.MERGE
    class Member{
        @OneToMany(mappedBy = "member", cascade = CascadeType.MERGE)
        private List<Order> orderList = new ArrayList<>();
    }
    
    Member member = new Member();
    Order order1 = new Order();
    Order order2= new Order();
    
    member.addOrder(order1);
    member.addOrder(order2);
    
    member = em.merge(member);
    
    Order order3 = new Order();
    member.addOrder(order3); 
    // order1, order2 insert 됨
    

    - CascadeType.MERGE는 flush랑 관련없다네...? - em.merge 메서드에 전달한 엔티티까지만 연쇄적으로 merge가 된대 - DB에서 merge가 뭐야?

  • DB에서 Merge? - 조건에 따라서 데이터의 삽입/갱신/삭제 작업한번에
  • hibernate? - ORM 프레임워크 - 레드햇이 만든 ORM 프레임워크 - JPA 가이드라인의 구현체 - JPA 프로바이더임
  • JPA? - 이건 그냥 구현체가 아니라 명세일뿐이야