본문 바로가기
학습/DB

Cascade 활용하기

코동이 2021. 9. 26.

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