💡영속성 전이 (CASCADE)
영속성 전이(CASCADE)는 데이터베이스의 관계형 데이터베이스 관리 시스템에서 사용되는 개념으로, 부모 엔티티의 영속성 상태 변화가 자식 엔티티에도 영향을 미치는 것을 말합니다. 이는 주로 ORM(Object-Relational Mapping) 기술을 사용하는 애플리케이션에서 엔티티 사이의 관계를 관리할 때 사용됩니다.
CASCADE 옵션은 부모 엔티티의 영속성 상태 변화가 일어났을 때, 그 영향이 자식 엔티티에 자동으로 전이되도록 설정하는 기능을 제공합니다. 이로써 부모 엔티티의 상태 변화에 따라 자식 엔티티도 일괄적으로 상태 변화를 일으키며, 데이터 일관성을 유지할 수 있습니다.
CASCADE 옵션은 다양한 관계에서 사용될 수 있습니다. 주요한 릴레이션 종류는 다음과 같습니다:
- One-to-One 관계: 일반적으로 부모 엔티티가 삭제되면 자식 엔티티도 삭제될 수 있습니다. 반대로 자식 엔티티를 삭제해도 부모 엔티티에는 영향을 미치지 않습니다.
- One-to-Many 관계: 일반적으로 부모 엔티티가 삭제되면 연관된 모든 자식 엔티티들도 삭제될 수 있습니다. 그러나 자식 엔티티의 삭제가 부모 엔티티에 영향을 미치지는 않습니다.
- Many-to-One 관계: Many-to-One 관계에서는 보통 부모 엔티티의 상태 변화가 자식 엔티티에도 영향을 미치지 않습니다. 부모 엔티티를 삭제해도 자식 엔티티에 영향을 주지 않는 경우가 일반적입니다.
- Many-to-Many 관계: Many-to-Many 관계에서 CASCADE 옵션은 다소 복잡할 수 있습니다. 예를 들어 두 엔티티 간의 연관 관계를 해제할 때 어떻게 동작할지 설정하는 등의 다양한 케이스가 있을 수 있습니다.
CASCADE 옵션은 데이터베이스 스키마 설계 및 애플리케이션 동작에서 중요한 역할을 합니다. 그러나 사용할 때 주의해야 할 점도 있습니다:
- 무분별한 사용으로 데이터 일관성 유지에 문제가 생길 수 있습니다.
- CASCADE DELETE를 사용할 경우 실수로 연관된 모든 데이터를 삭제하는 상황이 발생할 수 있습니다.
- 데이터베이스의 CASCADE 옵션을 사용할 때는 그에 따른 쿼리 및 성능 이슈를 고려해야 합니다.
따라서 CASCADE 옵션을 사용할 때는 신중하게 상황을 판단하고 데이터 일관성을 유지하기 위해 적절한 설정을 해야 합니다.
📋CASCADE 사용 예제
CASCADE를 사용한 예제를 하나 들어보겠습니다. 회원(Member) 엔티티와 해당 회원이 작성한 게시글(Post) 엔티티 간에 One-to-Many 관계가 있다고 가정해봅시다. CASCADE를 사용하여 회원을 삭제할 때 해당 회원의 모든 게시글도 함께 삭제되도록 설정해볼 것입니다.
===== 회원 엔티티 =====
@Entity
public class Member {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String username;
// 다른 멤버필드, Getter,Setter등은 생략
@OneToMany(mappedBy = "writer", cascade = CascadeType.ALL, orphanRemoval = true)
private List<Post> posts = new ArrayList<>();
}
===== 게시글 엔티티 =====
@Entity
public class Post {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String title;
private String content;
// 다른 게시필드, Getter,Setter등은 생략
@ManyToOne
@JoinColumn(name = "writer_id")
private Member writer;
}
위의 코드에서 Member 엔티티의 posts 필드에 @OneToMany 어노테이션에 cascade 속성을 CascadeType.ALL로 설정했습니다.
이는 Member 엔티티의 상태 변화(예: 삭제)가 해당 회원의 모든 게시글에도 전이되도록 지정하는 것입니다. 또한 orphanRemoval = true 설정으로 연관 관계가 끊어질 때 해당 게시글을 자동으로 제거합니다.
이제 만약 특정 회원을 삭제하면, 해당 회원의 모든 게시글도 자동으로 삭제됩니다.
@Service
@Transactional
public class MemberService {
// MemberService methods...
public void deleteMember(Long memberId) {
Member member = memberRepository.findById(memberId).orElse(null);
if (member != null) {
memberRepository.delete(member);
}
}
}
위의 deleteMember 메서드를 호출하여 특정 회원을 삭제하면, 해당 회원의 CASCADE 설정에 따라 모든 게시글도 함께 삭제될 것입니다.
JPA에서는 다양한 종류의 Cascade 옵션을 제공하여 영속성 전이 동작을 지원합니다. 각 Cascade 옵션은 엔티티의 상태 변화가 다른 연관 엔티티에 어떻게 전파되는지를 정의합니다. 주요한 Cascade 옵션은 다음과 같습니다:
- CascadeType.ALL : 모든 상태 변화를 전이합니다. 해당 엔티티의 PERSIST, MERGE, REMOVE, REFRESH, DETACH 등의 모든 작업이 연관된 엔티티에도 적용됩니다.
- CascadeType.PERSIST : 엔티티가 영속 상태로 전이될 때, 해당 엔티티의 상태 변화를 연관된 엔티티에도 전이시킵니다.
- CascadeType.MERGE : 엔티티의 변경이 병합될 때(merge) 해당 엔티티의 상태 변화를 연관된 엔티티에도 전이시킵니다.
- CascadeType.REMOVE : 엔티티가 삭제될 때, 해당 엔티티의 상태 변화를 연관된 엔티티에도 전이시킵니다.
- CascadeType.REFRESH : 엔티티를 새로고침(refresh)할 때, 해당 엔티티의 상태 변화를 연관된 엔티티에도 전이시킵니다.
- CascadeType.DETACH : 엔티티를 분리(detach)할 때, 해당 엔티티의 상태 변화를 연관된 엔티티에도 전이시킵니다.
- CascadeType.NONE : 어떤 상태 변화도 전이하지 않습니다. 연관된 엔티티의 상태는 변경되지 않습니다.
그 외의 사용자 정의 Cascade 옵션: JPA 구현체나 프레임워크에서 사용자가 직접 정의한 Cascade 옵션입니다. 예를 들어 Hibernate에서는 CascadeType.PERSIST와 CascadeType.MERGE를 결합한 CascadeType.PERSIST_AND_MERGE 옵션이 있습니다.
Cascade 옵션은 각각의 상황과 데이터 모델에 따라 적절하게 선택하여 사용해야 합니다. 잘못된 Cascade 옵션 사용은 의도하지 않은 동작을 초래할 수 있으므로 신중하게 선택해야 합니다.
💡 고아객체 (Orphan Removal)
고아객체(Orphan Removal)는 JPA에서 관계가 끊어진 엔티티를 자동으로 삭제해주는 기능을 말합니다. 이는 연관 관계에서 부모 엔티티와 연결되어 있는 자식 엔티티가 더 이상 해당 부모와의 연관 관계를 갖지 않을 때, 자동으로 삭제되도록 설정하는 것을 의미합니다.
예를 들어, 부모 엔티티에서 자식 엔티티의 컬렉션을 가지고 있고 이 컬렉션의 연관 관계를 끊게 되면, 고아객체 설정이 활성화되어 있다면 해당 자식 엔티티가 데이터베이스에서 삭제됩니다.
고아객체 설정을 사용하면 불필요한 데이터를 데이터베이스에 남기지 않고 자동으로 관리할 수 있습니다. 하지만 주의해야 할 점은, 고아객체 설정을 사용할 경우에는 해당 자식 엔티티를 사용하는 모든 곳에서 주의해서 다루어야 합니다. 만약에 다른 곳에서 해당 자식 엔티티를 다시 참조하려는 경우에 문제가 발생할 수 있습니다.
✍️ 고아객체 사용 예제
고아객체 설정은 @OneToOne, @OneToMany 어노테이션의 orphanRemoval 속성으로 활성화할 수 있습니다. 예를 들어, 다음과 같이 사용할 수 있습니다
@Entity
public class Parent {
@OneToMany(mappedBy = "parent", orphanRemoval = true)
private List<Child> children = new ArrayList<>();
// ...
}
@Entity
public class Child {
@ManyToOne
private Parent parent;
// ...
}
Parent findParent = em.find(Parent.class, parent.getId());
findParent.getChildList().remove(0);
위의 코드에서 orphanRemoval = true로 설정되어 있기 때문에, Parent 엔티티와 연관된 Child 엔티티가 끊어질 경우 자동으로 삭제됩니다.
참조가 제거된 엔티티는 다른 곳에서 참조하지 않는 고아객체로 보고 삭제하는 기능입니다. 주의점은 특정 엔티티가 개인 소유할 때 사용해야하며, 참조하는 곳이 하나일 때 사용해야합니다. @OneToOne , @OneToMany만 가능합니다.
이론적으로는 부모를 제거하면 자식이 고아가 되기때문에 객체 제거 기능을 활성화 하면, 부모를 제거할 때 자식도 함께 제거됩니다. CascadeType.REMOVE 처럼 동작합니다.
===== Member 엔티티에서의 연관관계 설정시, orphanRemoval = true ======
@OneToMany(mappedBy = "parent", orphanRemoval = true)
private List<Child> childList = new ArrayList<>();
===== main메서드에서 parent 객체를 em.remove ======
Parent findParent = em.find(Parent.class, parent.getId());
em.remove(findParent);
Parent만 remove했지만 child도 모두 지워집니다.
✍️ CascadeType.ALL과 orphanRemoval = true를 함께 사용
✅ 관련된 엔티티를 완전히 제어하면서 데이터 일관성과 무결성을 유지하기 위해
CascadeType.ALL은 부모 엔티티의 상태 변화가 자식 엔티티에 전이되도록 설정하는 것입니다. 이것은 부모 엔티티에 대한 변경이 자식 엔티티에도 자동으로 전이되어 부모-자식 간의 관계를 편리하게 관리할 수 있게 해줍니다. 예를 들어, 부모 엔티티가 삭제될 때 자식 엔티티도 함께 삭제됩니다.
orphanRemoval = true는 연관 관계가 끊어진 자식 엔티티를 자동으로 삭제하도록 설정하는 것입니다. 이는 자식 엔티티가 더 이상 부모 엔티티와 연관 관계를 갖지 않을 때, 자동으로 삭제되도록 해줍니다. 이것은 자식 엔티티를 효과적으로 관리하면서 데이터베이스의 일관성을 유지하는 데 도움을 줍니다.
따라서 CascadeType.ALL과 orphanRemoval = true를 함께 사용하면, 부모 엔티티의 모든 상태 변화가 자식 엔티티에 전이되고, 자식 엔티티와 부모 엔티티 간의 연관 관계가 끊어진 경우 자식 엔티티가 자동으로 삭제됩니다. 두 옵션을 활성화하게 되면부모 엔티티를 통해서 자식의 생명주기를 관리할 수 있습니다. 이렇게 함으로써 데이터베이스 내의 엔티티 간의 관계를 관리하고 데이터 무결성을 보장할 수 있게 됩니다.
'[ BACKEND] > Spring' 카테고리의 다른 글
[SPRING] 값 타입 컬렉션 (0) | 2023.08.21 |
---|---|
[SPRING] 기본 값 타입 (0) | 2023.08.20 |
[SPRING] 즉시 로딩과 지연 로딩 (0) | 2023.08.18 |
[SPRING] ✅ Proxy (0) | 2023.08.17 |
[SPRING] 고급 매핑 - 구현 클래스 , 조인 전략 (0) | 2023.08.16 |