Reference. 한 번에 끝내는 Java/Spring 웹 개발 마스터 초격차 패키지 Online
이전 글
더보기
1. Cascade (영속성 전이)
- 영어로는 폭포를 의미하며 단계별로 전이가 발생
@OneToOne
,@OneToMany
,@ManyToOne
연관 관계가 있는 어노테이션에cascade()
지원
CascadeType.java
에는ALL
,PERSIST
,MERGE
,REMOVE
,REFRESH
,DETACH
속성 지원DETACH
: 준영속(detach)으로 변경할 때 연관 엔티티도 준영속
REFRESH
: 엔티티를 다시 로드할 때, 연관 엔티티도 재로드
ALL
: 모든 경우에 연관 엔티티 전파
- JPA는 자바코드를 SQL쿼리로 번역해주는 ORM
save()
를 자주 사용함으로 자바관점에선 불필요한 코드 사용(save는 영속화 시키기 위함)
@SpringBootTest class BookRepositoryTest { @Autowired private BookRepository bookRepository; @Autowired private PublisherRepository publisherRepository; ... @Test void bookCascadeTest(){ Book book = new Book(); book.setName("JPA 책"); bookRepository.save(book); //Book Entity 영속화 Publisher publisher = new Publisher(); publisher.setName("테스트 출판사"); publisherRepository.save(publisher); //Publisher Entity 영속화 book.setPublisher(publisher); //Book Entity에 영속화된 Publisher 수정 bookRepository.save(book); publisher.addBook(book); //Publisher Entity에 영속화된 Book 수정 publisherRepository.save(publisher); System.out.println("books : " + bookRepository.findAll()); System.out.println("publishers : " + publisherRepository.findAll()); } }
- 영속성 전이를 이용해 객체 중심의 코드 수정이 가능
- 엔티티를 영속화하지 않아도 엔티티간 관계 설정이 가능 (
save()
)
@ManyToOne(cascade = {CascadeType.PERSIST, CascadeType.MERGE})
로 연관관계 적용
PERSIST(등록)
,MERGE(수정)
등을 할 때 영속성 전이가 발생
- 엔티티를 영속화하지 않아도 엔티티간 관계 설정이 가능 (
... public class Book extends BaseEntity{ ... @ManyToOne(cascade = {CascadeType.PERSIST, CascadeType.MERGE}) @ToString.Exclude private Publisher publisher; }
@SpringBootTest class BookRepositoryTest { ... @Test void bookCascadeTest(){ Book book = new Book(); book.setName("JPA 책"); Publisher publisher = new Publisher(); publisher.setName("테스트 출판사"); //비영속화 상태에서 엔티티간 연관관계 맺기가 안됌 (cascade로 연관관계 맺음) book.setPublisher(publisher); bookRepository.save(book); System.out.println("books : " + bookRepository.findAll()); System.out.println("publishers : " + publisherRepository.findAll()); Book book1 = bookRepository.findById(1L).get(); book1.getPublisher().setName("변경된 출판사"); bookRepository.save(book1); System.out.println("publishers : " + publisherRepository.findAll()); } }
//실행결과 books : [Book(super=BaseEntity(createdAt=2021-08-08T19:01:18.537728, updatedAt=2021-08-08T19:01:18.537728), id=1, name=JPA 책, category=null)] publishers : [Publisher(super=BaseEntity(createdAt=2021-08-08T19:01:18.588729, updatedAt=2021-08-08T19:01:18.588729), id=1, name=테스트 출판사)] publishers : [Publisher(super=BaseEntity(createdAt=2021-08-08T19:01:18.588729, updatedAt=2021-08-08T19:01:19.107600), id=1, name=변경된 출판사)]
2. 삭제처리, 고아제거 속성
cascade 삭제
Book.java (CascadeType.REMOVE
추가)
@Entity
@NoArgsConstructor
@Data
@ToString(callSuper = true)
@EqualsAndHashCode(callSuper = true)
public class Book extends BaseEntity{
...
@ManyToOne(cascade = {CascadeType.PERSIST, CascadeType.MERGE, CascadeType.REMOVE})
@ToString.Exclude
private Publisher publisher;
...
}
BookRepositoryTest.java
@SpringBootTest
class BookRepositoryTest {
@Autowired
private BookRepository bookRepository;
@Autowired
private PublisherRepository publisherRepository;
...
@Test
void bookRemoveCascadeTest(){
bookRepository.deleteById(1L); //cascade 삭제속성으로 연관엔티티 관계제거
System.out.println("books : " + bookRepository.findAll());
System.out.println("publishers : " + publisherRepository.findAll());
bookRepository.findAll().forEach(book -> System.out.println(book.getPublisher()));
}
}
고아제거 속성
- 연관관계가 없는 엔티티를 제거하는 속성
- 연관관계를 제거하는 방법은 setter에 null값을 주입
Hibernate: update book_and_author set book_id=null where book_id=? Hibernate: update review set book_id=null where book_id=? Hibernate: update book set publisher_id=null where publisher_id=? Hibernate: delete from book where id=? Hibernate: delete from publisher where id=?
CascadeType.REMOVE
,orphanRemoval
의 특징- 설정하는 방법 (엔티티 속성)
CascadeType.REMOVE
:@ManyToOne(cascade = {CascadeType.REMOVE})
설정
orphanRemoval
:@OneToMany(orphanRemoval = true)
설정
- 동작의 차이
CascadeType.REMOVE
:- 상위객체의 remove 이벤트를 하위 엔티티에 영속성 이벤트를 전파하여 삭제
setter
를 통해 null을 실행하면 관련된 엔티티가 삭제 안됌 (데이터 보존)
orphanRemoval
:setter
를 통해 null을 실행하면 관련된 엔티티가 삭제
- 설정하는 방법 (엔티티 속성)
소프트 delete 처리 (flag 사용)
- 상용화 된 시스템에는 delete 삭제를 하지 않고 삭제 flag 컬럼을 생성 후 조건으로 검색
- 아래의 예시는
deleted
flag 컬럼을 설정하고 true는 삭제로 판단- java boolean타입은 db에 0과 1로 표시 (0: false, 1: true)
data.sql
...
insert into book(`id`, `name`, `publisher_id`, `deleted`) values(1, 'JPA 초격자 패키지', 1, false);
insert into book(`id`, `name`, `publisher_id`, `deleted`) values(2, 'Spring', 1, false);
insert into book(`id`, `name`, `publisher_id`, `deleted`) values(3, 'Spring Security', 1, true);
Book.java
...
public class Book extends BaseEntity{
...
private boolean deleted;
}
BookRepository.java
@Repository
public interface BookRepository extends JpaRepository<Book, Long> {
...
List<Book> findAllByDeletedFalse();
List<Book> findByCategoryIsNullAndDeletedFalse();
}
BookRepositoryTest.java
@SpringBootTest
class BookRepositoryTest {
...
@Test
void softDelete() {
bookRepository.findAllByDeletedFalse().forEach(System.out::println);
bookRepository.findByCategoryIsNullAndDeletedFalse().forEach(System.out::println);
}
}
//findAllByDeletedFalse
Hibernate:
select
book0_.id as id1_2_,
book0_.created_at as created_2_2_,
book0_.updated_at as updated_3_2_,
book0_.category as category4_2_,
book0_.deleted as deleted5_2_,
book0_.name as name6_2_,
book0_.publisher_id as publishe7_2_
from
book book0_
where
book0_.deleted=0
Book(super=BaseEntity(createdAt=null, updatedAt=null), id=1, name=JPA 초격자 패키지, category=null, deleted=false)
Book(super=BaseEntity(createdAt=null, updatedAt=null), id=2, name=Spring, category=null, deleted=false)
//findByCategoryIsNullAndDeletedFalse
Hibernate:
select
book0_.id as id1_2_,
book0_.created_at as created_2_2_,
book0_.updated_at as updated_3_2_,
book0_.category as category4_2_,
book0_.deleted as deleted5_2_,
book0_.name as name6_2_,
book0_.publisher_id as publishe7_2_
from
book book0_
where
(
book0_.category is null
)
and book0_.deleted=0
Book(super=BaseEntity(createdAt=null, updatedAt=null), id=1, name=JPA 초격자 패키지, category=null, deleted=false)
Book(super=BaseEntity(createdAt=null, updatedAt=null), id=2, name=Spring, category=null, deleted=false)
repository
에 매번 메소드를 추가하는 것은 불편하고 다른 버그가 발생할 확률 다수
Entity
에@Where
를 추가하고 조건문 생성@Where(clause = "deleted = false") public class Book extends BaseEntity{ ... }
'백엔드 > JPA' 카테고리의 다른 글
[ JPA ] 9. 임베디드 타입 활용 (0) | 2021.08.18 |
---|---|
[ JPA ] 8. 커스텀 쿼리 사용 (0) | 2021.08.18 |
[ JPA ] 6-4. 트랜잭션 매니저 (TransactionManager) (0) | 2021.08.08 |
[ JPA ] 6-3. Entity 생명주기 (1) | 2021.08.08 |
[ JPA ] 6-2. Entity 캐시 (0) | 2021.08.07 |