본문 바로가기
학습/DB

고아제거 속성 알아보기

코동이 2021. 9. 26.

cascade의 삭제에 대해서 알아본다. 이전에 book 클래스는 PERSISTMERGE만 적용하고 있었다.

 

public class Book {
...
@ManyToOne(cascade = {cascade = CascadeType.PERSIST, cascade = CascadeType.MERGE})
@ToString.Exclude
private Publisher publisher;
...
}

 

 

* cascade 제거 확인하기 ( Book N : 1 Publisher )

 

@Test
void bookCascadeTest() {
  Book book = new Book();
  book.setName("JPA 초격자 패키지");
  
  Publisher publisher = new Publisher();
  publisher.setName("fastcampus");
  
  book.setPublihser(publisher);
  bookRepository.save(book);
  
  Book savedBook = bookRepository.findById(1L).get();
  savedBook.getPublisher().setName("슬로우캠퍼스");
  
  bookRepository.save(savedBook);
  
  System.out.println(publisherRepository.findAll());
  
  Book deteledBook = bookRepository.findById(1L).get();
  bookRepository.delete(deletedBook); //book만 삭제!
  
  System.out.println(bookRepository.findAll());
  System.out.println(publisherRepository.findAll()); //정상적으로 book이 삭제될까?
  
}

 

PERSISTMERGE만 있기 떄문에 book만 삭제한다고해도, publisher까지 삭제되지 않는다. 

 

public class Book {
...
@ManyToOne(cascade = {cascade = CascadeType.PERSIST, cascade = CascadeType.REMOVE})
@ToString.Exclude
private Publisher publisher;
...
}

 

마찬가지로, cascade에 REMOVE를 추가해야 한다.

 

 

* 부모 객체를 제거하기

 

@Test
void bookRemoveCascadeTest() {
  bookRepository.deleteById(1L);
  
  bookRepository.findAll().forEach(book -> System.out.println(bookgetPublisher())); 
  //publisher도 삭제될까?
}

 

book 객체를 제거하면, 연관된 publisher 객체가 제거된다.

 

*orphanRemoval

 orphanRemoval은 연관관계가 끊기는 경우 연관된 객체가 제거가 된다. 즉, 부모의 삭제여부와 상관없이 "고아"가 된다면 삭제가 된다.

 

@Test
void bookCascadeTest() {
  Book book = new Book();
  book.setName("JPA 초격자 패키지");
  
  Publisher publisher = new Publisher();
  publisher.setName("fastcampus");
  
  book.setPublihser(publisher);
  bookRepository.save(book);
  
  Book savedBook = bookRepository.findById(1L).get();
  savedBook.getPublisher().setName("슬로우캠퍼스");
  
  bookRepository.save(savedBook);
  
  System.out.println(publisherRepository.findAll());
  
  Book cascadeBook = bookRepository.findById(1L).get();
  cascadeBook.setPubhlisher(null); //연관관계 제거!
  
  System.out.println(publisherRepository.findAll()); //publisher는 삭제될까?
}

 

REMOVE는 연관관계가 제거된다고 해도, 연관된 publisher는 삭제되지 않는다.

 

orphanRemoval = true를 설정하고 다시 테스트한다. 이 경우, 연관관계가 끊어지기만해도 연관된 엔티티는 삭제된다.

 

public class Publisher {
...
@OneToMany(orphanRemoval = true)
@JoinColumn(name = "publisher_id")
@ToString.Exclude
private List<Book> books = new ArrayList<>();
...
}

 

* orphanRemoval=true  vs  CascadeType.REMOVE

 

1. 부모가 삭제된다면, orphanRemoval와 REMOVE 모두 자식을 삭제한다.

2. 부모와 자식의 관계를 끊어버리면 ( ex Parent의 Child를 null로 변경)

  2-1) orphanRemoval은 부모와의 관계가 끊어져 고아가 되었으므로 삭제된다.

  2-2) REMOVE의 경우, 부모를 삭제한 것이 아니므로 자식을 삭제하지 않는다.

 

운영에서는, 보통 delete로 엔티티를 삭제하지 않는다, 대신에 private boolean deleted; 칼럼을 추가해서 삭제 여부를 변경하도록 한다. 기존 객체 이력이 남는 장점이 있다.

 

List<Book> findByDeletedFalse();

List<Book> findByCategoryIsNullAndDeletedFalse();

 

조회를 할 때 deleted 칼럼이 있다면, 꼭 DeletedFalse를 붙여서 삭제되지 않는 것들만 조회하도록 유의한다.

 

@Where(close = "deleted = false")
public class Book {
...

 

@Where를 선언하면, Book의 쿼리문을 실행할 때마다 삭제여부를 검사한다.

반응형

'학습 > DB' 카테고리의 다른 글

Native Query  (0) 2021.09.30
@Transactional  (0) 2021.09.26
Cascade 활용하기  (0) 2021.09.26
@Query 활용하기 2  (0) 2021.09.26
@Query 활용하기 1  (0) 2021.09.26