쉬운 프로그래밍

[JPA] Entity Status와 Cascade란 무엇일까? 본문

Programming/JPA

[JPA] Entity Status와 Cascade란 무엇일까?

쉬운형 2021. 2. 25. 12:04

Cascade란?

cascade는 @ManyToOne이나 @OneToMany에 들어갈 수 있는 옵션이다.

 

트랜잭션이 일어날 때 Entity 변화를 연관관계를 가진 Entity에 전파시키는 것을 목적으로 한다.

 

Entity 상태란?

1. Transient : JPA가 알지 못하는 상태를 의미한다. 즉 객체를 생성하거나 변경하여도 JPA가 그 객체를 인지하지 못하고 있는 상태를 의미한다.

 

2. Persistent : JPA가 관리중인 상태를 의미한다. Persistent 상태가 되더라도 바로 Insert가 발생해서 데이터베이스에 저장하는 것이 아닌, Persistent에서 관리하고 있던 객체가 데이터베이스에 넣는 시점에 데이터를 저장함 (1차 캐싱, Dirty Checking, Write Behind 등 기능 제공)

 

3. Detached : JPA가 더이상 객체를 관리하지 않는 상태를 의미한다.

 

4. Removed : JPA가 현재 시점에는 관리하고 있지만 곧 삭제하기로 한 상태를 의미한다.

 

cascade 옵션은 위에서 설명한 상태 변화를 전파시키는 과정으로 생각할 수 있다.

 

 

Cascade 옵션 적용

Cascade는 주로 Parent - child 관계를 가지고 있는 엔티티들에게 적용된다.

 

먼저 코드를 통해 Cascade를 적용하지 않은 엔티티부터 살펴보겠다.

 

Parent Entity (Post 클래스)

@Entity
public class Post {

    @Id 
    @GeneratedValue
    private Long id;
    private String title;

    @OneToMany(mappedBy = "post")
    private Set<Comment> comments = new HashSet<>();
    
    public void addComment(Comment comment) {
        this.getComments().add(comment);
        comment.setPost(this);
    }
}

Child Entity (Child 클래스)

@Entity
public class Comment {

    @Id
    @GeneratedValue
    private Long id;
    private String comment;

    @ManyToOne
    private Post post;
}

 

위 엔티티들에 대하여 아래와 같이 post 데이터를 저장시켜보겠다.

@Component
@Transactional
public class JpaRunner implements ApplicationRunner {

    @PersistenceContext
    EntityManager entityManager;

    @Override
    public void run(ApplicationArguments args) throws Exception {
        Post post = new Post();
        post.setTitle("Spring Data JPA 언제 보나...");

        Comment comment = new Comment();
        comment.setComment("빨리 보고 싶엉.");
        post.addComment(comment);

        Comment comment1 = new Comment();
        comment1.setComment("곧 보여드릴께요.");
        post.addComment(comment1);

        Session session = entityManager.unwrap(Session.class);
        session.save(post);
    }
}

위와 같이 post를 save 하는 경우에는 cascade를 적용하지 않았기 때문에 post만 저장되고,

 

comment에 전파되지 않는다. 즉 post 테이블에만 데이터가 저장될 것이다.

 

하지만 아래와 같이 Post 엔티티 내에서 cascade 옵션을 준다면 comment도 같이 저장이 될 것이다.

@OneToMany(mappedBy = "post", cascade = CascadeType.PERSIST)
private Set<Comment> comments = new HashSet<>();

public void addComment(Comment comment) {
    this.getComments().add(comment);
    comment.setPost(this);
}

 

Post 객체가 Transient state에서 Persistent state로 넘어갈 때 cascade 옵션을 통해 @OneToMany 관계로 연결되어 있는 Comment 객체도 Persistent 상태가 되어 comment 또한 같이 저장된다.

 

@OneToMany(mappedBy = "post", cascade = {CascadeType.PERSIST, CascadeType.REMOVE})
private Set<Comment> comments = new HashSet<>();

public void addComment(Comment comment) {
    this.getComments().add(comment);
    comment.setPost(this);
}

CascadeType.REMOVE를 적용하였을 때도 마찬가지이다.

 

Post를 삭제할 경우에 Post Entity가 Removed state가 되면 comment들에게도 Removed state가 전파되어 트랜잭션이 커밋될 때 데이터가 함께 모두 삭제된다.

 

@OneToMany(mappedBy = "post", cascade = CascadeType.ALL)
private Set<Comment> comments = new HashSet<>();

public void addComment(Comment comment) {
    this.getComments().add(comment);
    comment.setPost(this);
}

일반적으로는 위와 같이 cascade = CascadeType.ALL 옵션을 통해 모든 state들을 전파하도록 한다.

 

 

#참고 : 백기선님의 스프링 데이터 JPA 강의

Comments