본문으로 바로가기

[CASCADE] 영속성 전이 , orphanRemoval = true

category Spring & JPA 2020. 4. 1. 16:05
영속성 컨텍스트(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 옵션이 바로 고아객체를 삭제해주는 옵션이다.