| 일 | 월 | 화 | 수 | 목 | 금 | 토 |
|---|---|---|---|---|---|---|
| 1 | 2 | 3 | 4 | |||
| 5 | 6 | 7 | 8 | 9 | 10 | 11 |
| 12 | 13 | 14 | 15 | 16 | 17 | 18 |
| 19 | 20 | 21 | 22 | 23 | 24 | 25 |
| 26 | 27 | 28 | 29 | 30 | 31 |
- queue
- 제로베이스
- 프로그래머스
- 자료구조
- spring
- QueryDSL
- array
- error
- LinkedList
- 서버
- 컴퓨터 공학
- TestCode
- 백엔드스쿨
- spring boot
- restTemplate
- 개발자
- 백준
- 핵심가이드
- 연관관계
- JPA
- Java
- SpringBoot
- ORM
- actuator
- JWT
- SpringSecurity
- 백엔드
- 컴퓨터 구조
- 백엔드공부
- 스프링부트
- Today
- Total
be_better
[Springboot] 연관관계 매핑 - 영속성 전이 본문
목차
영속성 전이
영속성 전이(cascade)란 특정 엔티티의 영속성 상태를 변경할 때 그 엔티티와 연관된 엔티티의 영속성에도 영향을 미쳐 영속성 상태를 변경하는 것을 의미한다.
@OneToMany 어노테이션의 인터페이스를 살펴보면 영속성 전이를 설정하는데 활용되는 cascade()라는 요소가 있다.
public @interface OneToMany {
Class targetEntity() default void.class;
CascadeType[] cascade() default {};
FetchType fetch() default LAZY;
String mappedBy() default "";
boolean orphanRemoval() default false;
}
cascade() 요소와 함께 사용하는 영속성 전이 타입은 다음과 같다.
- ALL: 모든 영속 상태 변경에 대해 영속성 전이를 적용
- PERSIST: 엔티티가 영속화할 때 연관된 엔티티도 함께 영속화
- MERGE: 엔티티를 영속성 컨텍스트에 병합할 때 연관된 엔티티도 병합
- REMOVE: 엔티티를 제거할 때 연관된 엔티티도 제거
- REFRESH: 엔티티를 새로고침할 때 연관된 엔티티도 새로고침
- DETACH: 엔티티를 영속성 컨텍스트에서 제외하면 연관된 엔티티도 제외
한 엔티티가 cascade 요소의 값으로 주어진 영속 상태의 변경이 일어나면 매핑으로 연관된 엔티티에도 동일한 동작이 일어나도록 전이를 발생시키는 것이다.
영속성 전이 적용
공급업체 엔티티 Provider 에 영속성 전이 설정
@OneToMany(mappedBy = "provider", cascade = CascadeType.PERSIST)
@ToString.Exclude
private List<Product> productList = new ArrayList<>();
영속성 전이 테스트
@Test
void cascadeTest() {
Provider provider = savedProvider("새로운 공급업체");
Product product1 = savedProduct("상품1", 1000, 1000);
Product product2 = savedProduct("상품2", 500, 1500);
Product product3 = savedProduct("상품3", 750, 500);
// 연관관계 설정
product1.setProvider(provider);
product2.setProvider(provider);
product3.setProvider(provider);
provider.getProductList().addAll(Lists.newArrayList(product1, product2, product3));
providerRepository.save(provider);
}
private Provider savedProvider(String name) {
Provider provider = new Provider();
provider.setName(name);
return provider;
}
private Product savedProduct(String name, Integer price, Integer stock) {
Product product = new Product();
product.setName(name);
product.setPrice(price);
product.setStock(stock);
return product;
}
실행 결과

지금까지는 각 ProductRepository에 save() 메서드를 통해 각각의 Product들을 데이터베이스에 저장하는 코드를 작성해야 했다. 하지만 영속성 전이를 사용하면 부모 엔티티가 되는 Provider 엔티티만 저장하면 코드에 작성되어 있는 Cascase.PERSIST에 맞춰 Product 엔티티도 함께 저장할 수 있다.
REMOVE와 REMOVE를 포함하는 ALL 같은 타입을 무분별하게 사용하면 연관된 엔티티가 의도치 않게 모두 삭제될 수 있기 때문에 코드들이 정확히 어떤 영향을 미치는지 파악할 필요가 있고 다른 타입보다 더욱 사이드 이펙트(side effect)를 고려해서 사용해야 한다.
고아 객체
JPA에서 고아(orphan)란 부모 엔티티와 연관관계가 끊어진 엔티티를 의미한다. JPA에는 이러한 고아 객체를 자동으로 제거하는 기능이 있다. 물론 자식 엔티티가 다른 엔티티와 연관관계를 가지고 있다면 이 기능은 사용하지 않는 것이 좋다.
공급업체 엔티티 Provider에 고아 객체를 제거하는 기능 추가
@OneToMany(mappedBy = "provider",
cascade = CascadeType.PERSIST,
orphanRemoval = true)
@ToString.Exclude
private List<Product> productList = new ArrayList<>();
'orphanRemoval = true' 추가 후 테스트 진행
Test code
@Test
@Transactional
void orphanRemovalTest() {
Provider provider = savedProvider("새로운 공급업체");
Product product1 = savedProduct("상품1", 1000, 1000);
Product product2 = savedProduct("상품2", 500, 1500);
Product product3 = savedProduct("상품3", 750, 500);
// 연관관계 설정
product1.setProvider(provider);
product2.setProvider(provider);
product3.setProvider(provider);
provider.getProductList().addAll(Lists.newArrayList(product1, product2, product3));
providerRepository.saveAndFlush(provider);
providerRepository.findAll().forEach(System.out::println);
productRepository.findAll().forEach(System.out::println);
Provider foundProvider = providerRepository.findById(1L).get();
foundProvider.getProductList().remove(0);
providerRepository.findAll().forEach(System.out::println);
productRepository.findAll().forEach(System.out::println);
}
실행 결과

앞서 저장한 세개의 상품들을 출력하는 것을 볼 수 있다.
이후 고아 객체를 생성하기 위해 List에서 remove()를 수행한 후 select 구문을 살펴보면

연관관계가 끊긴 상품의 엔티티가 삭제된 것을 확인 할 수 있다. Hibernate에서는 상태 감지를 통해 삭제하는 쿼리가 자동으로 수행되는 것을 볼 수 있다.
'Springboot > 이론' 카테고리의 다른 글
| [Springboot] 유효성 검사와 예외 처리 - 예외 처리 (0) | 2023.11.28 |
|---|---|
| [Springboot] 유효성 검사와 예외 처리 - 유효성 검사 (0) | 2023.11.28 |
| [Springboot] 연관관계 매핑 - 다대다 매핑 (0) | 2023.11.18 |
| [Springboot] 연관관계 매핑 - 다대일, 일대다 매핑 (0) | 2023.11.17 |
| [Springboot] 연관관계 매핑 - 종류, 일대일 매핑 (0) | 2023.11.17 |