[JPA] 영속성 전이 (CASCADE)와 고아 객체
1. CASCADE
- 특정 Entity를 영속 상태로 만들 때, 연관된 Entity들에 대해 영속성을 전파 시키는 옵션.
- @OneToMany, @ManyToOne 어노테이션에서 사용이 가능하며 기본 설정으로 사용하지 않게 되어 있다.
예제
@Entity
public class Person {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private int id;
private String name;
@OneToMany(mappedBy = "person")
private List<Address> addresses;
public void addAddress(Address address){
addresses.add(address);
addresses.setPerson(this);
}
}
@Entity
public class Address {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private int id;
private String street;
private int houseNumber;
private String city;
private int zipCode;
@ManyToOne(fetch = FetchType.LAZY)
private Person person;
}
- 위와 같은 엔티티들이 있다고 가정하자.
1. 기본적인 영속석 저장
Address address1 = new Address();
Address address2 = new Address();
Person person = new Person();
person.addAddress(address1);
person.addAddress(address2);
em.persist(person);
em.persist(address1);
em.persist(address2);
- persist를 세 번 호출해야 정상적으로 동작함. 연관된 객체만큼 persist를 호출하므로 보기에도 비효율적인 코드다.
2. CASCADE를 이용한 영속성 저장
@Entity
public class Person {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private int id;
private String name;
@OneToMany(mappedBy = "person", cascade=CascadeType.ALL)
private List<Address> addresses;
public void addAddress(Address address){
addresses.add(address);
addresses.setPerson(this);
}
}
- 위와 같이 @OneToMany에서 cascade 속성을 정의해주자
Address address1 = new Address();
Address address2 = new Address();
Person person = new Person();
person.addAddress(address1);
person.addAddress(address2);
em.persist(person);
- persist 메서드로 person을 저장하면 그와 연관된 엔티티 객체들도 같이 영속성 저장이 된다.
CASCADE의 타입
- ALL: 모든 Cascade 타입 적용.
- PERSIST: persist 메서드 호출 시 연관된 엔티티 저장
- REMOVE: remove 메서드 호출 시 연관된 엔티티 제거
- MERGE: merge 메서드 호출 시 연관된 엔티티들 병합
- REFRESH: refresh 메서드 호출 시 인스턴스의 값을 다시 읽어 옴 (새로 고침)
- DETACH: detach 메서드 호출 시 연관된 엔티티들까지 준영속 상태로 변환
영속성 전이를 사용할 수 있는 경우
- 전이 대상이 한 군데에서만 사용되면 써도 좋으나, 하위 엔티티가 상위 엔티티에만 종속되지 않고 여러군데에서 사용되면 영속성 전이를 사용하지 않는게 좋다.
- 요약하면
- 서로의 라이프 사이클이 같을 때
- 어떤 엔티티를 오직 자신만이 소유하고 있을 때, 즉 단일 소유자 관계인 경우
- ex) 회원 엔티티와과 팀 엔티티가 연관되어있고, 회원 엔티티와 라커 엔티티가 연관되어 있다고 가정할 때, 팀을 삭제하면 회원 엔티티가 영속성 전이에 의해 지워진다. 라이프 사이클이 같지 않은 라커 엔티티는 회원 엔티티를 사용할 때 이슈가 발생하게 된다.
2. 고아 객체
- 고아 객체는 부모 엔티티가 사라진 자식 엔티티를 말한다.
예제
1. 부모와 연관된 자식을 삭제했을 경우
public class Person {
.
.
.
@OneToMany(mappedBy = "person", cascade=CascadeType.ALL, orphanRemoval = true)
private List<Address> addresses;
.
.
}
Address address1 = new Address();
Address address2 = new Address();
Person person = new Person();
person.addAddress(address1);
person.addAddress(address2);
em.flush();
em.clear();
Person person1 = em.find(Person.class, person.getId());
person.getAddresses().remove(0);
- 두 개의 주소를 만들고 Person에 저장 후, Address Collection에 맨 처음 저장된 객체를 삭제했다. 기본적으로 Person이 주 관계이기 때문에 remove와 관련된 변화는 없어야한다.
- 하지만 실제 remove 메서드가 실행 뒤 delete 쿼리가 DB에 날아가게 되고, DB에서도 하나의 row가 삭제된 것을 볼 수 있다.
2. 부모를 삭제했을 경우
Address address1 = new Address();
Address address2 = new Address();
Person person = new Person();
person.addAddress(address1);
person.addAddress(address2);
em.flush();
em.clear();
Person person1 = em.find(Person.class, person.getId());
em.remove(person1);
- Person 객체와 연관된 모든 child들이 고아 객체가 되고 orphanRemoval이 true이므로 고아가 된 객체는 삭제가 된다.
영속성 전이 + 고아 객체 자동 삭제
- 도메인 주도 설계(DDD)의 Aggregate Root 개념을 구현할 때 유용하게 사용이 된다.
- 부모 엔티티로 자식 엔티티의 생명 주기를 관리할 수 있다.
- Cascade는 부모의 영속 상태가 변하면 자식도 같이 변한다. 즉 remove로 부모 객체 엔티티를 삭제하면 자식도 삭제되지만, 부모 엔티티 객체에서 자식 엔티티 객체를 삭제한다고 객체의 참조가 지워지는 것이지 자식 엔티티 객체가 지워지지 않는다.
- 부모 객체에서 자식 객체를 지울 때는 orphanRemoval(고아객체 삭제)를 true로 설정하면 된다.
Author And Source
이 문제에 관하여([JPA] 영속성 전이 (CASCADE)와 고아 객체), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다
https://velog.io/@daehoon12/JPA-영속성-전이Cascade
저자 귀속: 원작자 정보가 원작자 URL에 포함되어 있으며 저작권은 원작자 소유입니다.
우수한 개발자 콘텐츠 발견에 전념
(Collection and Share based on the CC Protocol.)
public class Person {
.
.
.
@OneToMany(mappedBy = "person", cascade=CascadeType.ALL, orphanRemoval = true)
private List<Address> addresses;
.
.
}
Address address1 = new Address();
Address address2 = new Address();
Person person = new Person();
person.addAddress(address1);
person.addAddress(address2);
em.flush();
em.clear();
Person person1 = em.find(Person.class, person.getId());
person.getAddresses().remove(0);
Address address1 = new Address();
Address address2 = new Address();
Person person = new Person();
person.addAddress(address1);
person.addAddress(address2);
em.flush();
em.clear();
Person person1 = em.find(Person.class, person.getId());
em.remove(person1);
Author And Source
이 문제에 관하여([JPA] 영속성 전이 (CASCADE)와 고아 객체), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://velog.io/@daehoon12/JPA-영속성-전이Cascade저자 귀속: 원작자 정보가 원작자 URL에 포함되어 있으며 저작권은 원작자 소유입니다.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)