cascade는 폭포라는 뜻으로, 폭포를 흘려보내듯이 하나의 영속성을 다른 객체로 전이하는 것이다.
@OneToMany, @OneToOne, @ManyToMany에서 cascade 설정이 가능하다. cascade 종류 6가지는 다음과 같다.
ALL, PERSIST, MERGE, REMOVE, REFRESH, DETACH
ALL | 모든 5개 종류 적용 |
PERSIST | 저장 같이한다. |
MERGE | 수정 적용한다. |
REMOVE | 삭제 같이한다. |
REFRESH | 재로딩 같이한다. |
DETACH | 영속성 컨텍스트에서 같이 분리한다. |
* Book 1 : N publisher로 설정된 관계에서 테스트진행
@Test
void bookCascadeTest() {
Book book = new Book();
book.setName("JPA 초격자 패키지");
bookRepository.save(book);
Publisher publisher = new Publisher();
publisher.setName("fastcampus");
pulisherRepository.save(publisher);
book.setPublihser(publisher);
bookRepository.save(book);
publisher.getBooks().add(book);
publisherRepository.save(publisher);
}
모든 엔티티에 서로의 값을 넣어주고 둘 다 save()를 하는 것이 일반적이다. publisher.getBooks().add(book);을 해도 정상적으로 book이 추가되는 이유는, 자바의 call by reference 특징에 의해 주소값을 참조하여 처리할 수 있기 떄문이다.
만약 no Session 오류가 나온다면, 보통 트랜잭션이 존재하지 않는다는 의미로, LAZY 로딩과 관련이 있다. @Test 위에 @Transactional을 추가하든지, 엔티티에서 연관관계가 있는 칼럼에서 @ToString.Exclude로 순환참조를 끊어주어야 한다.
cascade 옵션을 사용하면, publisher를 따로 save()하지 않아도, book만 save()를 해주어도 저장이 된다. cascade를 사용하면 book.setPublisher(publisher);를 통해 영속성이 전이되기 때문에, publisher도 자동으로 book을 가지게 된다.
public class Book {
...
@ManyToOne(cascade = CascadeType.PERSIST)
@ToString.Exclude
private Publisher publisher;
...
}
@Test
void bookCascadeTest() {
Book book = new Book();
book.setName("JPA 초격자 패키지");
Publisher publisher = new Publisher();
publisher.setName("fastcampus");
book.setPublihser(publisher);
bookRepository.save(book);
//publisher.getBooks().add(book);
//publisherRepository.save(publisher);
}
publihserRepository.save(publisher);를 하지 않아도 insert 구문이 2개 생성된다.
* cascade 수정 확인하기
@Test
void bookCascadeTest() {
Book book = new Book();
book.setName("JPA 초격자 패키지");
Publisher publisher = new Publisher();
publisher.setName("fastcampus");
book.setPublihser(publisher);
bookRepository.save(book);
//publisher.getBooks().add(book);
//publisherRepository.save(publisher);
Book savedBook = bookRepository.findById(1L).get();
savedBook.getPublisher().setName("슬로우캠퍼스");
bookRepository.save(savedBook);
System.out.println(publisherRepository.findAll());//book의 name이 바뀌었을까?
}
저장된 book을 다시 조회해서 수정할 때는 publisher의 book name이 바뀌지 않는다. 이는, @ManyToOne(cascade = CascadeType.PERSIST) 속성 때문인데, PERSIST는 저장할 때만 영속성 전이가 일어나므로 업데이트에는 작동하지 않는다.
public class Book {
...
@ManyToOne(cascade = {cascade = CascadeType.PERSIST, cascade = CascadeType.MERGE})
@ToString.Exclude
private Publisher publisher;
...
}
업데이트도 cascade로 전이하기 위해서, PERSIST 뿐만 아니라 MERGE도 추가한다.
REMOVE는 원치 않는 객체를 삭제 할 수도 있으므로 주의해서 사용한다.
cascade는 default는 빈 배열이므로 아무런 작동도 하지 않는다.
'학습 > DB' 카테고리의 다른 글
@Transactional (0) | 2021.09.26 |
---|---|
고아제거 속성 알아보기 (0) | 2021.09.26 |
@Query 활용하기 2 (0) | 2021.09.26 |
@Query 활용하기 1 (0) | 2021.09.26 |
Transaction 격리수준 (0) | 2021.09.26 |