728x90

 

 

 

01. 영속성 전이: CASCADE

 

 

 

사용 목적

특정 엔티티를 영속 상태로 만들 때 연관된 엔티티도 함께 영속 상태로 만들고 싶을 때 사용한다.

 

예시로 부모 엔티티를 저장할 때 자식 엔티티도 함께 저장하고 싶을 때가 있다.

 

 

 

영속성 전이(CASCADE)를 사용하지 않는다면?

위의 Parent와 Child에 대한 예시로 코드를 작성해보겠다. Child와 Parent는 다대일 양방향 연관관계를 갖는다.
다음은 Child 클래스 코드이다.

 

@Entity
public class Child {
@Id
@GeneratedValue
private Long id;
private String name;
@ManyToOne
@JoinColumn(name = "parent_id")
private Parent parent;
// 생성자, getter/setter
}

 

 

다음은 Parent 클래스 코드이다.

 

@Entity
public class Parent {
@Id
@GeneratedValue
private Long id;
private String name;
@OneToMany(mappedBy = "parent")
private List<Child> childList = new ArrayList<>();
// 연관관계 편의 메소드
public void addChild(Child child) {
childList.add(child);
child.setParent(this);
}
// 생성자, getter/setter
}

 

 

다음은 JpaMain 코드이다. Parent 중심으로 개발을 했지만, Parent와 Child를 따로 persist 해야한다.

 

Child child1 = new Child();
Child child2 = new Child();
Parent parent = new Parent();
parent.addChild(child1);
parent.addChild(child2);
em.persist(parent);
em.persist(child1);
em.persist(child2);
tx.commit();

 

실행 결과로 쿼리가 세 번 나가는 것을 볼 수 있다.

 

 

 

 

영속성 전이(CASCADE)를 사용한다면?
Parent를 persist하면 Child도 자동으로 persist 되었으면 좋겠다를 반영하기 위해 CASCADE를 사용해보자.

Parent를 클래스의 childList에 cascade 속성(cascade = CascadeType.ALL))을 추가하자.

 

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

 

JpaMain에서 Child를 persist 하는 코드를 다음과 같이 제거하자. 코드 상으로는 마치 Parent만 persist 하는 것 처럼 보인다.

 

Child child1 = new Child();
Child child2 = new Child();
Parent parent = new Parent();
parent.addChild(child1);
parent.addChild(child2);
em.persist(parent);
tx.commit();

 

실행결과로 Parent만 persist 했는데 child도 persist 된 것을 볼 수 있다.

 

 

아래 그램은 @OneToMany(mappedBy="parent",cascade=CascadeType.PERSIST) 인 경우를 그림으로 나타낸 것이다.

 

 

 

 

CASCADE의 종류
ALL : CascadeType.PERSISTCascadeType.REMOVE의 기능을 모두 수행한다.
PERSIST : 부모를 영속화하면 자식도 같이 영속화 하고 싶을 때 사용한다.
REMOVE : PERSIST로 함께 저장했던 부모와 자식의 엔티티를 모두 제거할 경우에 사용한다.
그 외 MERGE, REFRESH, DETACH 가 있다.

 

 

 

CASCADE의 주의점
영속성 전이는 연관관계를 매핑하는 것과 아무 관련이 없다.
엔티티를 영속화 할 때 연관된 엔티티도 함께 영속화하는 편리함을 제공할 뿐이다.
단일 엔티티에 완전히 종속적일 때, lifeCycle이 같을 때 사용하면 된다.
그렇지 않고 다른 엔티티도 자식 엔티티와 연관관계가 있다면 사용하면 안된다.

 

 

 


 

 

 

02. 고아 객체

 

 

 

고아 객체란?

부모 엔티티와 연관관계가 끊어진 자식 엔티티를 말한다.

 

 

 

고아 객체를 제거하려면?
orphanRemoval = true 를 사용하면 된다. 예시로 보자.
Parent 클래스의 @OneToMany 속성에 orphanRemoval = true 를 추가한다.

 

@Entity
class Parent {
@OneToMany(mappedBy = "parent", cascade = CascadeType.ALL, orphanRemoval = true)
private List childList = new ArrayList<>();
}

 

 

다음은 JpaMain의 try문 코드이다. childList의 0번째 요소를 제거한다.

 

Child child1 = new Child();
Child child2 = new Child();
Parent parent = new Parent();
parent.addChild(child1);
parent.addChild(child2);
em.persist(parent);
em.flush();
em.clear();
Parent findParent = em.find(Parent.class, parent.getId());
findParent.getChildList().remove(0); // 자식 엔티티를 컬렉션에서 제거한다.
tx.commit();

 

 

실행 결과로 delete 쿼리가 나가는 것과 자식의 0번째 요소가 지워진 것을 확인할 수 있다.

 

 

 

 

 

고아 객체의 주의점
고아 객체를 제거하는 기능은, 참조가 제거된 엔티티는 다른 곳에서 참조하지 않는 고아 객체로 간주하여 삭제하는 기능이라고 정의할 수 있다.
참조하는 곳이 하나일 때, 특정 엔티티가 개인 소유일 때 사용하면 된다.
@OneToOne@OneToMany만 가능하다.

 

 


 

 

 

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

 

 

CasecadeType.ALL + orphanRemoval = true
스스로 생명주기를 관리하는 엔티티는 em.persist로 영속화하고 em.remove()로 제거한다.
두 옵션을 모두 활성화 하면 부모 엔티티를 통해 자식의 생명 주기를 관리할 수 있다.

 

Parent는 JPA의 EntityManager를 통해 생명주기가 관리되고, Child는 생명주기를 Parent가 관리한다.
이것은 도메인 주도 설계(DDD)의 Aggregate Root 개념을 구현할 때 유용하다.

 

728x90

'JPA' 카테고리의 다른 글

임베디드 타입  (0) 2024.01.15
기본값 타입  (2) 2024.01.14
즉시 로딩과 지연 로딩  (2) 2024.01.12
프록시  (0) 2024.01.12
@MappedSuperclass - 매핑 정보 상속  (0) 2024.01.11