[JPA] 영속성 전이와 고아 객체

ttaho·2023년 12월 21일
2

JPA

목록 보기
6/7

JPA의 영속성 전이와 고아 객체에 대해 알아보자.

영속성 전이 : CASCADE

영속성 전이는 왜 필요할까?

특정 엔티티를 영속 상태로 만들 때 연관된 엔티티도 함께 영속 상태로 만들고 싶을 수 있다. 이 작업을 간편하게 하기 위해 영속성 전이를 사용한다.

Parent.java

@Setter
@Getter
@Entity
public class Parent {

    @Id 
    @GeneratedValue
    @Column(name = "PARENT_ID")
    private Long id;

    private String name;

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

Child.java

@Getter
@Setter
@Entity
public class Child {

    @Id @GeneratedValue
    @Column(name = "CHILD_ID")
    private Long id;
    private String name;

    @ManyToOne
    private Parent parent;

}

Parent(부모) 엔티티와 Child(자식) 엔티티가 있고, 부모는 여러명의 자식을 가진다고 가정해보자.

	// 부모 저장
    Parent parent = new Parent();
    parent.setName("임종수");
    entityManager.persist(parent);
    
    // 1번 자식 저장
    Child child1 = new Child();
    child1.setName("임준영");
    child1.setParent(parent); // 자식 -> 부모 연관관계 설정
    parent.getChildren().add(child1); // 부모 -> 자식
    entityManager.persist(child1);

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

부모와 두 명의 자식을 저장하기 위해서는 모두 영속 상태여야 한다.
위의 코드는 부모와 두 명의 자식을 영속 상태로 만들기 위해 entityManager.persist를 세 번 호출해야 한다.
이럴 때 영속성 전이를 사용하면 부모 엔티티만 영속 상태로 만들면 연관된 자식까지 한번에 영속 상태로 만들 수 있다.

영속성 전이 : 저장

@Setter
@Getter
@Entity
public class Parent {

   @Id @GeneratedValue
   @Column(name = "PARENT_ID")
   private Long id;

   private String name;


   @OneToMany(mappedBy = "parent", cascade = CascadeType.PERSIST)
   private List<Child> children = new ArrayList<Child>();
}

cascade 옵션을 PERSIST로 설정한다. 해당 설정을 통해 부모를 영속상태로 만들게 되면 children에 속해있는 자식들도 영속 상태로 만들 수 있다.

	// 1번 자식 저장
    Child child1 = new Child();
    // 2번 자식 저장
    Child child2 = new Child();

    Parent parent = new Parent();
    parent.setName("부모부모");
    
    child1.setName("자식1");
    child2.setName("자식2");
  
    child1.setParent(parent); // 자식 -> 부모 연관관계 설정
    child2.setParent(parent); // 자식 -> 부모 연관관계 설정
    
    parent.getChildren().add(child1); // 부모 -> 자식
    parent.getChildren().add(child2); // 부모 -> 자식

    // 부모 저장
    entityManager.persist(parent);

주의사항

  • 영속성 전이는 연관관계를 매핑하는 것과 아무 관련이 없다!
  • 엔티티를 영속화할 때 연관된 엔티티도 함께 영속화하는 편리함을 제공할 뿐이다.

CASCADE의 종류

영속성 전이는 저장 외에도 사용할 수 있다.

public enum CascadeType{

    ALL, // 모두적용
    PERSIST, // 영속
    MERGE, // 병합
    REMOVE, // 삭제
    REFRESH, // REFRESH
    DETACH // DETACH
}

참고로 CascadeType.PERSIST, CascadeType.REMOVE는 em.persist(), em.remove()를 실행 할 때 바로 전이가 발생하지 않고 플러시를 호출 할 때 전이가 발생합니다.

고아 객체

JPA는 부모 엔티티와 연관관계가 끊어진 자식 엔티티인 고아 객체를 자동으로 삭제하는 기능을 제공한다.
즉, 부모 엔티티의 컬렉션에서 자식 엔티티의 참조를 제거하면 자식 엔티티가 자동으로 삭제되도록 할 수 있다.

@Setter
@Getter
@Entity
public class Parent {

    @Id @GeneratedValue
    @Column(name = "PARENT_ID")
    private Long id;

    private String name;

    @OneToMany(mappedBy = "parent", orphanRemoval = true)
    private List<Child> children = new ArrayList<Child>();
}

orphanRemovel = true 설정을 하게 되면
아래의 코드에서 부모 엔티티의 컬렉션에 0번째 자식을 삭제하게 되면 자식 엔티티의 Delete 쿼리가 발생한다.

Parent parent1 = em.find(Parent.class, id); 
parent1.getChildren().remove(0); 
//자식 엔티티를 컬렉션에서 제거 

주의사항

  • 해당 기능은 참조가 제거된 엔티티는 다른 곳에서 참조하지 않는 고아 객체로 보고 삭제하는 기능이다.
  • 그러므로 참조하는 곳이 하나일 때 사용해야한다!! -> 특정 엔티티가 개인 소유할 때 사용(매우 중요)
  • @OneToOne, @OneToMany만 가능
  • 부모 제거 -> 자식은 고아가 됨. 따라서 고아 객체 제거 기능을 활성화 한다는 말은 부모 제거시, 자식도 함께 제거한다는 말이다. 이것은 CascadeType.REMOVE 처럼 동작한다.

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

CascadeType.ALL + orphanRemoval = true

위 처럼 두 옵션을 활성화 하면 부모 엔티티를 통해자식의 생명주기를 관리할 수 있다

//자식을 저장하려면 부모에 등록만 하면 됨.
Parent parent = em.find(Parent.class , parentId);
parent.addChild(child); // 이건 편의메소드로 따로 만들어줘야함

//자식을 삭제하려면 부모에서 제거하면 됨.
Parent parent = em.find(Parent.class , parentId);
parent.getChildren().remove(removeObject);
profile
백엔드 꿈나무

0개의 댓글