영속성 전이 : 특정 엔티티를 영속 상태로 만들 때 연관된 엔티티도 함께 영속 상태로 만들고 싶을 때 사용
영속 상태 : 영속성 컨텍스트에 저장된 상태
→ 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 엔티티만 삭제됨
- 영속성 컨텍스트에서의 작업:
- entityManager.remove(post)가 호출되면, post 엔티티는 영속성 컨텍스트에서 제거되고, 삭제 작업이 예약됨
- 하지만 CascadeType.REMOVE가 설정되지 않았기 때문에 comment 엔티티는 여전히 영속성 컨텍스트에 남아있고, 삭제되지 않음
- 데이터베이스로의 반영:
- flush 또는 트랜잭션 커밋 시점에, 영속성 컨텍스트의 변경 사항이 데이터베이스에 반영
- 이때 post 엔티티에 대한 삭제 쿼리가 실행
- 외래 키 제약 조건 위반:
- 데이터베이스에서 post 엔티티가 삭제될 때, comment 테이블에 post의 외래 키가 설정되어 있다면 무결성 제약 조건을 위반 → 예외 발생
따라서, 이 경우 예외가 발생하여 트랜잭션이 롤백되어 결과적으로 post와 comment 모두 삭제되지 않음
참고
https://tecoble.techcourse.co.kr/post/2023-08-14-JPA-Cascade/
https://hyeooona825.tistory.com/87
https://hanumoka.github.io/post/jpa_cascade_vs_mappedby/
'JPA' 카테고리의 다른 글
[JPA] JPQL과 방언(Dialect) (0) | 2024.05.27 |
---|---|
[JPA] Fetch type, N+1 문제 (0) | 2024.05.23 |