JPA 영속성 전이 (CASCADE) 와 고아 객체(ORPHAN)


영속성 전이 (CASCADE) 란?


영속성 전이 (CASCADE) 란 특정 엔티티를 영속성 상태로 만들때 연관되어진 엔티티도 함께 영속성 상태로 변경 하는 것을 말합니다. 아래 예를 살펴 보겠습니다.

    Shop shop = new Shop();
    shop.setName("JPA마켓");
    em.persist(shop);       //영속성 상태변경
    
    Shop_Payments payment = new Shop_Payments();
    payment.setName("JPA간편페이");
    payment.setShop(shop);
    em.persist(payment);    //영속성 상태변경
    
    Shop_Order order = new Shop_Order();
    order.setName("봉골레");
    order.setPayments(payment);
    em.persist(order);      //영속성 상태변경

예에서 보면 3번의 영속성 상태 변경이 일어났습니다. 부모인 Shop 엔티티를 생성 하여 영속성 상태로 변경 한뒤 자식 테이블도 생성 하여 영속성 상태를 변경 하였습니다.
JPA 에서는 부모 엔티티를 영속성 상태로 변경 하면 자식도 함께 변경 될 수 있도록 하는 기능을 제공 하는데 이를 영속성 전이(CASCADE) 라고 합니다.

  • 영속성 전이 옵션 정보
옵션 정보
CascadeType.ALL 모두 적용
CascadeType.PERSIST 영속
CascadeType.MERGE 병합
CascadeType.REMOVE 삭제
CascadeType.REFRESH REFRESH
CascadeType.DETACH DETACH

영속성 상태 저장(CascadeType.PERSIST)


영속성 상태 저장을 사용 하기 위해서는 CascadeType.PERSIST 옵션을 설정 하여 영속성 상태 변경을 하면 됩니다.

  • 맴버, 강사 엔티티

      @Entity
      @Table(name="MEMBER")
      public class Member {
          @Id
          private String id;
            
          private String name;
            
          @ManyToOne(cascade = CascadeType.PERSIST)    //영속성 전이 설정
          @JoinColumn(name = "TEACHER_ID")
          private Teacher teacher;
          //...getter, setter
      }
        
      @Entity
      public class Teacher {
            
          @Id @GeneratedValue
          @Column(name = "TEACHER_ID")
          private long id;
            
          @Column(name = "TEACHER_NAME")
          private String name;
            
          public Teacher() {
          }
        
          public Teacher(String name) {
              this.name = name;
          }
      }
    
  • 테스트

      //트랜잭션 시작
      tx.begin(); 
        
      Teacher teacher = new Teacher("김일타");
        
      Member member1 = new Member("1", "홍길동");
      member1.setTeacher(teacher);
        
      em.persist(member1);	//영속성 상태 변경
        
      tx.commit();
    

테스트 코드를 실행 해보면 정상적으로 데이터가 입력 된것을 확인 할 수 있습니다.
강사 엔티티는 영속성 상태 변경을 하지 않았지만 영속성 전이를 통해서 멤버 엔티티를 영속성 상태 변경 했기 때문에 함께 저장이 되었습니다.

영속성 상태 삭제(CascadeType.REMOVE)


영속성 상태에서 삭제를 하기 위해서는 아래 예와 같이 자식 엔티티를 삭제 한뒤 부모 엔티티를 삭제 해야 합니다.

Member member = em.find(Member.class, "1");
Teacher teacher = em.find(Teacher.class, "1");
em.remove(teacher);
em.remove(member);

@ManyToOne(cascade = CascadeType.REMOVE) 옵션을 설정 하면 부모를 삭제 하면 연관된 자식도 삭제가 됩니다.

Member member = em.find(Member.class, "1");
em.remove(member);

고아 객체(ORPHAN) 란?

부모 엔티티와 연관관계가 끊어진 자식 엔티티를 자동으로 삭제 하는 기능을 고아 객체 라고 합니다. 예시를 보고 고아 객체를 확인 해보겠습니다.

  • 맴버, 강사 엔티티

      @Entity
      @Table(name="MEMBER")
      public class Member {
      	@Id @GeneratedValue
      	@Column(name = "MEMBER_ID")
      	private long id;
        	
      	@Column(name = "MEMBER_NAME")
      	private String name;
        	
      	@OneToMany(mappedBy = "member", cascade = CascadeType.PERSIST, orphanRemoval = true)    //고아 객체 설정
      	private List<Teacher> teacher  = new ArrayList<>();
          // getter, setter
      }
      
      @Entity
      public class Teacher {
        	
      	@Id @GeneratedValue
      	@Column(name = "TEACHER_ID")
      	private long id;
        	
      	@Column(name = "TEACHER_NAME")
      	private String name;
        	
      	@ManyToOne
      	@JoinColumn(name = "MEMBER_ID")
      	private Member member;
      	// getter, setter
      }
    
  • 테스트

      Teacher teacher1 = new Teacher("김일타");
      Teacher teacher2 = new Teacher("박이타");
        
      Member member = new Member("홍길동");
      member.addTeacher(teacher1);
      member.addTeacher(teacher2);
        
      teacher1.setMember(member);
      teacher2.setMember(member);
        
      em.persist(member);	//영속성 상태 변경
        
      member.getTeacher().remove(1);    //강사 컬렉션에서 삭제
    

테스트 코드를 수행 하면 멤버와 강사가 insert 된 후 컬렉션에서 제거 했던 강사 엔티티에 delete 를 수행 하는 것을 확인 할 수 있습니다.

마무리

오늘은 영속성 전이와 고아 객체에 대해서 정리 해보았습니다.
영속성 전이와 고아 객체의 사용 법을 익히고 자식 엔티티의 생명 주기를 관리 할 수 있을 것입니다.

Back to blog