본문 바로가기
JPA

[JPA] 영속성 전이 : CASCADE

by qoth_0 2024. 5. 23.
728x90
반응형

 

영속성 전이 : 특정 엔티티를 영속 상태로 만들 때 연관된 엔티티도 함께 영속 상태로 만들고 싶을 때 사용

영속 상태 : 영속성 컨텍스트에 저장된 상태

→  JPA에서 엔티티를 저장할 때 연관된 모든 엔티티는 영속 상태여야 함

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

 

영속성 컨텍스트 : 엔티티를 연구적으로 저장해주는 환경

→  애플리케이션과 데이터베이스 사이에서 객체를 보관하는 가상의 데이터베이스 같은 역할

→  엔티티 매니저를 통해 엔티티를 저장하거나 조회하면 엔티티 매니저는 영속성 컨텍스트에 엔티티를 보관하고 관리

 

JPA Cascade란?

엔티티의 생명 주기 상태 변화가 연관된 엔티티에 자동으로 전파되게 하는 옵션

즉, 한 엔티티를 저장, 수정, 삭제할 때 이와 연관된 다른 엔티티들도 자동으로 같은 연산이 적용되게 하는 기능

 

예를들어, ‘댓글’은 ‘게시물'에 깊게 연관되어 있음

→  ‘댓글’ 엔티티는 ‘게시물’ 엔티티가 없다면 존재 의의가 없기 때문

// PostService.java
@Transactional
public void deletePost(Long postId) {
    Post post = postRepository.findById(postId);
    List<Comment> comments = post.getComments();

    commentRepository.deleteAll(comments); // 댓글 삭제
    postRepository.delete(post); // 게시글 삭제
}

 

위와 같이 게시물을 삭제하는 비즈니스 로직을 작성할 때의 의문점

  • 게시물을 삭제할 때 댓글을 삭제하는 로직을 번거롭게 항상 작성해 줘야 할까?
  • 실수로 댓글 삭제 로직을 빼먹을 수도 있지 않을까?
  • 보다 좋은 방법이 없을까?

→  JPA Cascade를 활용하면 ‘어떤 엔티티와 다른 엔티티가 밀접한 연관성이 있을 때’에 대한 관리가 매우 수월해짐

 

 

JPA Cascade Types

1.PERSIST

엔티티를 영속화할 때 연관된 엔티티도 함께 영속화하는 옵션

 

2. MERGE

엔티티 상태를 병합할 때 연관된 엔티티도 함께 병합

 

3. REMOVE

엔티티를 제거할 때 연관된 엔티티들도 함께 제거

 

4. REFRESH

엔티티를 새로고침할 때, 연관된 엔티티들도 함께 새로고침

 데이터베이스로부터 인스턴스 값을 다시 읽어 옴

 

5. DETACH

영속성 컨텍스트에서 Entity 제거

 

6. ALL

위에서 언급한 모든 Cascade Type들이 적용

 

 

CascadeType을 설정하지 않으면?

연관된 엔티티들이 제대로 처리되지 않으면, 데이터베이스 무결성 제약 조건에 의해 예외가 발생할 수 있음

예를 들어, 자식 엔티티가 존재하는데 부모 엔티티가 삭제되면 외래 키 제약 조건 위반 예외가 발생

@Entity
public class Post {

    @Id
    @GeneratedValue
    private Long id;

    private String title;

    @OneToMany(mappedBy = "post") // , cascade = ?
    private List<Comment> comments = new ArrayList<>();

    // 생성자 생략

    public void addComment(Comment comment) {
        comments.add(comment);
    }
  ...
}

Post 엔티티

 

@Entity
public class Comment {

    @Id
    @GeneratedValue
    private Long id;

    private String value;

    @ManyToOne
    @JoinColumn(name = "post_id")
    private Post post;
    ...
}

Comment 엔티티 

 

Post post = new Post();
Comment comment = new Comment();

post.addComment(comment);

entityManager.persist(post); // post 저장
entityManager.persist(comment); // comment 저장

entityManager.remove(post); // post 삭제

 

CascadeType.REMOVE를 설정하지 않고 위 코드 실행 시 post 엔티티만 삭제됨

 

  1. 영속성 컨텍스트에서의 작업:
    • entityManager.remove(post)가 호출되면, post 엔티티는 영속성 컨텍스트에서 제거되고, 삭제 작업이 예약됨
    • 하지만 CascadeType.REMOVE가 설정되지 않았기 때문에 comment 엔티티는 여전히 영속성 컨텍스트에 남아있고, 삭제되지 않음
  2. 데이터베이스로의 반영:
    • flush 또는 트랜잭션 커밋 시점에, 영속성 컨텍스트의 변경 사항이 데이터베이스에 반영
    • 이때 post 엔티티에 대한 삭제 쿼리가 실행
  3. 외래 키 제약 조건 위반:
    • 데이터베이스에서 post 엔티티가 삭제될 때, comment 테이블에 post의 외래 키가 설정되어 있다면 무결성 제약 조건을 위반 → 예외 발생

따라서, 이 경우 예외가 발생하여 트랜잭션이 롤백되어 결과적으로 post와 comment 모두 삭제되지 않음

 

 

 

 

 

 

참고

https://tecoble.techcourse.co.kr/post/2023-08-14-JPA-Cascade/

https://hyeooona825.tistory.com/87

https://velog.io/@neptunes032/JPA-%EC%98%81%EC%86%8D%EC%84%B1-%EC%BB%A8%ED%85%8D%EC%8A%A4%ED%8A%B8%EB%9E%80

https://hanumoka.github.io/post/jpa_cascade_vs_mappedby/

 

 

728x90
반응형

'JPA' 카테고리의 다른 글

[JPA] JPQL과 방언(Dialect)  (0) 2024.05.27
[JPA] Fetch type, N+1 문제  (0) 2024.05.23