JPA - 영속성 전이 & 고아 객체

DevSeoRex·2022년 11월 27일
0
post-thumbnail

영속성 전이 - CASCADE

  • 특정 엔티티를 영속 상태로 만들때 연관된 엔티티도 함께 영속상태로 만들때 사용한다.
  • JPA는 CASCADE 옵션으로 영속성 전이 기능을 제공한다.
// 영속성 전이 예제 - 엔티티 정의
@Entity
public class Parent {
	
    @Id @GeneratedValue
    private Long id;
    
    @OneToMany(mappedBy = "parent")
    private List<Child> children = new ArrayList<Child>();
    ...
}

@Entity
public class Child {
	
    @Id @GeneratedValue
    private Long id;
    
   @ManyToOne
   private Parent parent;
   ...
}

위와 같은 부모와 자식 엔티티가 있다고 하면, 부모 한명에 자식 두명을 저장할경우, 아래 코드와 같이 부모 한명과 자식 2명을 저장해야 하므로, 3번의 persist( ) 호출이 일어나야 한다.

// 영속성 전이를 설정하지 않았을때 연관관계 있는 엔티티들의 저장 예제

// 부모 저장
Parent parent = new Parent();
em.persist(parent);

// 1번 자식 저장
Child child1 = new Child();
child1.setParent(parent); // 자식 -> 부모 연관관계 설정
parent.getChildren().add(child1); // 부모 -> 자식
em.persist(child1);

// 2번 자식 저장
Child child2 = new Child();
child2.setParent(parent); // 자식 -> 부모 연관관계 설정
parent.getChildren().add(child2); // 부모 -> 자식
em.persist(child2);

💡 JPA에서 엔티티를 저장할 때 연관된 모든 엔티티는 영속 상태여야 한다.

위의 예제 코드에서는 부모 엔티티를 영속 상태로 만든 뒤, 자식 엔티티도 각각 영속 상태로 만들어야 한다.

영속성 전이를 사용하면 부모만 영속 상태로 만들면 연관된 자식까지 한 번에 영속 상태로 만들 수 있다.

영속성 전이 - 저장

  • 영속성 전이를 활성화 하고 싶다면, CASCADE옵션을 적용하면 된다.
// 영속성 전이 활성화 예제

@Entity
public class Parent {
	
    ...
    @OneToMany(mappedBy = "parent", cascad = CascadeType.PESIST)
    private List<Child> children = new ArrayList<Child>();
    ...
}

위의 예제처럼 영속성 전이를 활성화 할 경우, 부모 한명에 연관된 자식 두명을 저장하는 코드가 꽤나 줄어든다.

// 영속성 전이 활성화 후, 저장 예제

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

Parent parent = new Parent();
child1.setParent(parent);		// 연관관계 추가
child2.setParent(parent);		// 연관관계 추가
parent.getChildren().add(child1);
parent.getChildren().add(child2);

// 부모와 연관된 자식들 저장
em.persist(parent);
  • 부모만 영속화해도 CascadeType.PERSIST 옵션으로 인해 자식 엔티티까지 함께 영속화된다.

    💡 주의 : 영속성 전이는 연관관계를 매핑하는 것과는 아무 관련이 없다.

영속성 전이 - 삭제

영속성 전이는 엔티티를 삭제할 때도 사용할 수 있다.

// 영속성 전이를 사용하지 않는 삭제 예제
Parent findParent = em.find(Parent.class, 1L);
Child findChild1 = em.find(Child.class, 1L);
Child findChild2 = em.find(Child.class, 2L);

em.remove(findChild1);
em.remove(findChild2);
em.remove(findParent);

영속성 전이를 사용하지 않으면 저장과 같이, em.remove( )를 세번 호출해야한다.

// 영속성 전이를 사용하는 삭제 예제
Parent findParent = em.find(Parent.class, 1L);
em.remove(findParent);

💡 삭제 순서는 외래 키 제약조건을 고려해, 자식을 먼저 삭제하고 부모를 삭제한다.

위의 예제코드를 영속성 전이를 사용하지 않고 실행한다면, 부모 엔티티만 삭제된다.
하지만 데이터베이스의 외래 키 제약조건으로 인해, 예외가 발생한다.

CASCADE의 종류

// CASCADE 옵션을 정의한 ENUM 예제
public enum CascadeType {
	ALL,				// 모두 적용
    PERSIST,			// 영속
    MERGE,				// 병합
    REMOVE,				// 삭제
    REFRESH,			// REFRESH
    DETACH				// DETACH
}
  • 영속성 전이는 여러 속성을 같이 사용할 수 있다.
cascade = {CascadeType.PESIST , CasadeType.REMOVE}

고아 객체

  • JPA는 부모 엔티티와 연관관계가 끊어진 자식 엔티티를 자동으로 삭제하는 기능을 제공한다.
  • 부모 엔티티와 연관관계가 끊어진 자식 엔티티를 자동 삭제하는 것을 고아 객체(ORPHAN) 제거라 한다.
  • 부모 엔티티의 컬렉션에서 자식 엔티티의 참조만 제거하면 자식 엔티티가 삭제된다.
// 고아 객체 제거 기능 설정
@Entity
public class Parent {
	
    @Id @GeneratedValue
    private long id;
    
    @OneToMany(mappedBy = "parent", orphanRemoval = true)
    private List<Child> children = new ArrayList<Chlid>();
}

// 고아객체 삭제 예제
Parent parent1 = em.find(Parent.class, id);
parent1.getChildren().remove(0); // 자식 엔티티를 컬렉션에서 제거한다.

💡 고아 객체 제거 기능은 영속성 컨텍스트를 플러시할 때 적용된다.

  • 고아 객체 제거는 참조가 제거된 엔티티는 다른 곳에서 참조하지 않는 고아 객체로 보고 삭제하는 기능이다.
  • 이 기능은 참조하는 곳이 하나일 때만 사용해야 한다.
  • @OneToMany, @ManyToOne에만 사용가능하다.
  • 고아 객체 제거는 부모를 제거하면 자식도 같이 제거된다.

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

  • 영속성 전이와 고아 객체 제거를 동시에 사용하면, 부모 엔티티를 통해 자식의 생명주기를 관리할 수 있다.
  • 자식을 저장하려면 부모에 저장하고, 자식을 삭제하려면 부모에서 제거하면 된다.

💡 영속성 전이는 DDD(도메인 주도 개발)의 Aggregate Root 개념을 구현할 때 사용하면 편리하다.

출처 : 자바 ORM 표준 JPA 프로그래밍 기초편(인프런, 김영한) & 자바 ORM 표준 JPA 프로그래밍(에이콘, 김영한)

0개의 댓글