Cascade 옵션이란?
엔티티의 상태 변화를 전파시키는 옵션이다.
OneToMany와 ManyToOne로 양방향 관계를 맺는 엔티티의 상태 변화를 전이시킬 때 사용한다.
특정 엔티티를 영속 상태로 만들 때 연관된 엔티티도 함께 영속상태로 만듦
Transient : JPA가 엔티티를 모르는 상태, 즉 최초의 객체들이 생성된 단계
Persistent : JPA가 관리중인 상태, DB에 들어간 것을 의미하지는 않는다. 즉 save() 메소드를 사용했다고 해서 바로 DB에 insert 되는 것은 아니며 이 상태를 Persistent라고 부른다.( 1차 캐시, Dirty Checking, Write Behind 등)
Detached : JPA가 더이상 관리하지 않는 상태.
Removed : JPA가 관리하긴 하지만 삭제하기로 한 상태.
예시
@Entity
class Post (
@Id @GeneratedValue
val id:Long?,
val title:String
){
@OneToMany(mappedBy = "post",cascade = [CascadeType.ALL])
val comments:MutableSet<Comment> = HashSet()
fun addComment(comment:Comment){
this.comments.add(comment)
comment.post = this
}
}
@Component
class JpaRunner: ApplicationRunner{
@PersistenceContext
lateinit var entityManager: EntityManager;
// @Transactional이 적용된 메소드에는 트랜잭션이 적용된다. JPA를 사용할 땐 Transaction 애노테이션을 달아주도록 하자.
@Transactional
override fun run(args: ApplicationArguments?) {
val post = Post(null,"Spring Data JPA 언제 보냐")
val comment = Comment(null,"빨리 보고 싶어요",post)
post.addComment(comment)
val comment2 = Comment(null,"곧 보여드릴게요",post)
post.addComment(comment2)
// Session 클래스는 하이버네이트이다. 즉, JPA를 구현하는 하이버네이트 클래스를 가져와서 하이버네이트의 API를 사용할 수 있다.
val session = entityManager.unwrap(Session::class.java)
session.save(post)
val getPost = session.get(Post::class.java,1L)
session.delete(getPost)
}
테스트하면 Comment 테이블에서 삭제되는 Post 레코드의 PK를 FK로 갖고 있는 모든 레코드들이 삭제되는 것을 확인할 수 있다.
CascadeType.REMOVE
처럼 부모를 제거할 때 자식도 함께 제거됨
orphanRemoval = true
Parent parent = em.find(Parent.class, id);
parent.getChildren().remove(0);
// 자식 엔티티를 컬렉션에서 제거
DELETE FROM CHILD WHERE ID=?