JPA - 연속성 전이: CASCADE

이유석·2023년 2월 6일
1

JPA - Entity

목록 보기
12/14
post-thumbnail
post-custom-banner

Cascade 옵션 이란?

  • 엔티티의 상태 변화를 전파시키는 옵션입니다.

  • @ManyToOne, @OneToMany, @OneToOne 을 통해 연관관계를 맺은 엔티티 사이의 상태 변화를 전파시킵니다.

엔티티의 상태 (생명 주기)

  • JPA 의 영속성 컨텍스트가 관리하는 엔티티들의 생명 주기를 나타냅니다.

  1. 비영속 상태 (New / Trainsient)
    • 순수한 객체 상태입니다.
    • 영속성 컨텍스트가 엔티티를 모르는 상태, 즉 최초의 객체들이 생성된 단계 입니다.
Book book = new Book();
  1. 영속 상태 (Managed / Persistent)
    • EntityManager를 통해 엔티티를 영속성 컨텍스트에 저장한 상태입니다.
    • 영속성 컨텍스트가 해당 엔티티를 관리하게 되는 상태입니다.
entityManger.persist(book);
  1. 삭제 (Removed)
    • 엔티티를 연속성 컨텍스트와 DB에서 삭제한 상태입니다.
entityManger.remove(book);
  1. 준영속 상태 (Detached)
    • 영속성 컨텍스트에 저장되었다가 다시 분리된 상태입니다.
    • 더이상 영속성 엔티티가 관리하지 않기 때문에, 1차 캐시 등에서 모든 정보가 삭제됩니다.
entityManger.detach(book);

Cascade 옵션은 이러한 상태 변화를 연관된 엔티티에 전이시키는 옵션입니다.

Cascade 옵션

  • PERSIST
  • MERGE
  • REMOVE
  • REFRESH
  • DETACH
  • ALL

Cascade 옵션을 알아보기 위해 게시글(Post) 와 댓글(Comment)를 예시로 들어보겠습니다.

Post 클래스

@Entity
public class Post {

	@Id
    @GeneratedValue
    @Column(name = "POST_ID")
    private Long id;
    
    @Column(name = "TITLE")
    private String title;
    
    @OneToMany(mappedBy = "post")
    private List<Comment> commentList = new ArrayList<>();
    
    // constructor, getter, setter, ...
}

Comment 클래스

@Entity
public class Comment {

	@Id
    @GeneratedValue
    @COLUMN(name = "COMMENT_ID")
    private Long id;
    
    @Column(name = "CONTENT")
    private String content;
    
  	@ManyToOne
    @JoinColumn(name = "POST_ID")
    private Post post;
    
    // constructor, getter, setter, ...
}

CascadeType.PERSIST

  • 하위 엔티티까지 영속성을 전달합니다.

  • Post Entity를 저장하면 하위 엔티티인 Comment Entity도 저장합니다.

@Test
public void 부모엔티티_저장시_자식_엔티티도_함께_저장() {

	Post post = new Post();
    post.setTitle("게시글 제목");
    
    Comment comment1 = new Comment();
    comment1.setContent("댓글 1");
    Comment comment2 = new Comment();
    comment2.setContent("댓글 2");
    
    post.getCommentList().add(comment1);
    post.getCommentList().add(comment2);
    
    // 영속화 작업 수행
    entityManager.persist(post);
    entityManager.flush();
}
  • PERSIST 옵션으로 인하여, post 엔티티 영속화 시, [comment1, comment2] 또한 영속화 됩니다.

  • 위 코드를 실행하였을 때, 실행되는 SQL 은 아래와 같습니다.

INSERT INTO POST (POST_ID, TITLE) VALUES (0, '게시글 제목');
INSERT INTO COMMENT (COMMENT_ID, CONTENT, POST_ID) VALUES (0, '댓글 1', 0);
INSERT INTO COMMENT (COMMENT_ID, CONTENT, POST_ID) VALUES (1, '댓글 2', 0);

CascadeType.MERGE

  • 하위 엔티티까지 병합 작업을 지속합니다.

  • 조회한 Post Entity와 Comment Entity를 수정할때,
    Post Entity를 Merge 하면 하위 엔티티인 Comment Entity도 Merge 됩니다.

@Test
public void 부모엔티티_merge시_자식_엔티티도_함께_merge() {

	Post post = new Post();
    post.setTitle("게시글 제목");
    
    Comment comment1 = new Comment();
    comment1.setContent("댓글 1");
    Comment comment2 = new Comment();
    comment2.setContent("댓글 2");
    
    post.getCommentList().add(comment1);
    post.getCommentList().add(comment2);
    
    // 영속화 작업 수행 및 영속성 컨텍스트 초기화
    entityManager.persist(post);
    entityManager.flush();
    entityManager.clear();
    
    Post savedPost = entityManager.find(0L, Post.class);
    Comment savedComment = entityManager.find(0L, Comment.class);
    
    // 엔티티 수정
    savedPost.setTitle("게시글 수정 제목");
    savedComment.setContent("댓글 수정 1);
    
    // merge 작업 수행
    entityManager.merge(savedPost);
    entityManager.flush();
}
  • MERGE 옵션으로 인하여, post 엔티티 merge 시, comment1 또한 merge 됩니다.

  • 위 코드를 실행하였을 때, 실행되는 SQL 은 아래와 같습니다.

...

SELECT * FROM POST WHERE POST_ID = 0;
SELECT * FROM COMMENT WHERE COMMENT_ID = 0;

UPDATE POST SET TITLE = '게시글 수정 제목' WHERE POST_ID = 0;
UPDATE COMMENT SET CONTENT = '댓글 수정 1' WHERE COMMENT_ID = 0;

CascadeType.REMOVE

  • 하위 엔티티까지 삭제 작업을 지속합니다.

  • Post Entity를 삭제하면 연관된 하위 엔티티인 Comment Entity도 삭제됩니다.

@Test
public void 부모엔티티_삭제시_자식_엔티티도_함께_삭제() {

	Post post = new Post();
    post.setTitle("게시글 제목");
    
    Comment comment1 = new Comment();
    comment1.setContent("댓글 1");
    Comment comment2 = new Comment();
    comment2.setContent("댓글 2");
    
    post.getCommentList().add(comment1);
    post.getCommentList().add(comment2);
    
    // 영속화 작업 수행 및 영속성 컨텍스트 초기화
    entityManager.persist(post);
    entityManager.flush();
    entityManager.clear();
    
    Post savedPost = entityManager.find(0L, Post.class);
    
    // remove 작업 수행
    entityManager.remove(savedPost);
    entityManager.flush();
}
  • REMOVE 옵션으로 인하여, post 엔티티 remove 시, [comment1,comment2] 또한 remove 됩니다.

  • 위 코드를 실행하였을 때, 실행되는 SQL 은 아래와 같습니다.

...

SELECT * FROM POST WHERE POST_ID = 0;

DELETE FROM POST WHERE POST_ID = 0;
DELETE FROM COMMENT WHERE COMMENT_ID = 0;
DELETE FROM COMMENT WHERE COMMENT_ID = 1;

CascadeType.REFRESH

  • 데이터베이스로부터 엔티티 값을 다시 읽어옵니다.
    즉, 영속성 컨텍스트에 저장되어 있는 값을 새로고침 합니다.

  • Post Entity를 Refresh하면 연관된 하위 엔티티인 Comment Entity도 Refresh됩니다.

CascadeType.DETACH

  • 영속성 컨텍스트에 더이상 해당 엔티티를 관리하지 않습니다.

  • Post Entity를 Detach하면 연관된 하위 엔티티인 Comment Entity도 Detach됩니다.

CascadeType.ALL

  • 상위 엔티티의 모든 상태 변화 작업이 하위 엔티티에 전파됩니다.
    즉, 위 옵션들이 모두 적용된 상태입니다.
profile
소통을 중요하게 여기며, 정보의 공유를 통해 완전한 학습을 이루어 냅니다.
post-custom-banner

0개의 댓글