영속성 컨텍스트(persistence context) : 엔티티를 영구 저장하는 환경
특정 엔티티를 영속 상태로 만들 때 연관된 엔티티도 함께 영속 상태로 만들고 싶다면 CASCADE 기능을 사용하면 된다.
*JPA에서 엔티티를 저장할 때 연관된 엔티티는 모두 영속 상태이어야 한다.
@Entity
@Data
public class Person {
@Id
@GeneratedValue
private Long id;
@OneToMany(mappedBy ="person" , cascade= CascadeType.PERSIST)
private List<Child> children = new ArrayList<>();
}
위와 같이 cascade = CascadeType.PERSIST로 지정하면 부모를 영속화할 때 연관된 자식들도 함께 영속화 된다.
@Data
@Table(name = "MEMBER")
@Entity
public class Member {
@Id
@GeneratedValue
private Long id;
@Column(name = "NAME")
private String name;
@Column(name = "AGE")
private Integer age;
@OneToOne
@JoinColumn(name = "LOCKER_ID")
private Locker locker;
}
@Data
@Entity
@Table
public class Locker {
@Id
@GeneratedValue
private Long id;
@Column(name = "NAME")
private String name;
}
Member와 Locker의 1:1 맵핑 관계에서 아래 테스트 케이스를 살펴보자.
@Test
public void test() {
//given
Member member = new Member();
member.setName("andrew");
member.setAge(32);
Locker locker = new Locker();
locker.setName("1번 사물함");
member.setLocker(locker);
memberRepository.save(member);
lockerRepository.save(locker);
Member existMember = memberRepository.findById(member.getId()).get();
assertEquals(existMember.getLocker().getName(), "1번 사물함");
}
위 Test의 실행 결과는 실패한다. 그 이유는 locker 객체를 저장하기 전에 , 객체 생성만 하고 member의 setLocker의 인자로 넘겼기 때문이다. 즉 locker가 db에 save()메소드를 통해 저장되기도 전에 memberRepository.save()를 먼저 호출 해서 에러가 발생한 것이다.
첫번째 해결방법은 , 실행 순서를 수정하는것 이다.
lockerRepository.save(locker); 를 먼저 수행하고 ,
memberRepository.save(member)를 하면 오류 없이 정상적으로 test를 통과하게 된다.
두번째 방법으로는 cascade 옵션 추가이다.
member가 save()를 할 때, 연관관계(자식) 에 있는 locker도 자동으로 저장해주기 때문에 위와 같은 오류를 해결할 수 있다.
@OneToOne(cascade = CascadeType.ALL)
@JoinColumn(name = "LOCKER_ID")
private Locker locker;
orphanRemoval = true
-객체 내에 다른 객체를 가르키는 aggregation관계에 있는 변수를 가질 경우, 그 객체를 삭제할 때 내부에 포함된 객체들도 삭제를 할지에 대한 여부를 지정하는 내용이다.
@OneToMany(cascade = {CascadeType.ALL}, fetch = FetchType.EAGER, orphanRemoval = true)
대부분의 1:N 관계 테이블을 설정할 때 위와 같이 옵션을 추가한다.
자식 엔티티의 변경이 있다면, JPA에서 자식엔티티 수정은
insert -> update -> delete 순으로 이어지는데, 변경된 자식을 먼저 insert하고, 기존 자식을 NULL로 update 한다.
여기서 , orphanRemoval = true로 설정하면 NULL로 처리된 자식을 DELETE 한다.
PK값이 NULL 변한 자식은 고아객체라고 하는데 orphanRemoval 옵션이 바로 고아객체를 삭제해주는 옵션이다.
'Spring & JPA' 카테고리의 다른 글
[Spring Boot + JPA] 결제시스템 구현하기 + 포인트 충전 (아임포트) (6) | 2020.05.07 |
---|---|
[Spring] 비밀번호 암호화 SHA-256 / MD5 (0) | 2020.05.05 |
컨트롤러 클래스 없이 특정 view대한 컨트롤러 추가 addViewControllers (0) | 2020.05.05 |
[Spring Boot+JPA] 회원가입 구현시 아이디 중복체크, 유효성 검사 처리하기 (0) | 2020.04.20 |
mybatis vs jpa 차이점 (0) | 2020.01.19 |