본문 바로가기
  • 개발공부 및 일상적인 내용을 작성하는 블로그 입니다.
JPA

영속성 전이(CASCADE) 와 고아 객체 - 2

by 방구석 대학생 2020. 10. 17.

"인프런 - 자바 ORM 표준 JPA 프로그래밍 강의를 듣고 작성한 글 입니다."

www.inflearn.com/course/ORM-JPA-Basic#

 

자바 ORM 표준 JPA 프로그래밍 - 기본편 - 인프런

JPA를 처음 접하거나, 실무에서 JPA를 사용하지만 기본 이론이 부족하신 분들이 JPA의 기본 이론을 탄탄하게 학습해서 초보자도 실무에서 자신있게 JPA를 사용할 수 있습니다. 초급 웹 개발 프로그

www.inflearn.com

 

고아 객체란?

부모 Entity 와 연관관계가 끊어진 자식 Entity 를 자동으로 삭제하는 기능이다.

- orphanRemoval 라는 옵션을 사용한다.(orphanRemoval = true)

- Parent.java

@OneToMany(mappedBy = "parent", cascade = CascadeType.ALL, orphanRemoval = true)
private List<Child> childList = new ArrayList<>();

 

이전에 cascade 기능을 사용해 보면서 영속성 컨텍스트에 올라갔던 데이터들을 flush, clear 를 통해 DB 에 쿼리를 전달하여 데이터를 테이블에 저장한 후, 아래와 같은 코드를 작성하여 애플리케이션을 실행해보자.

- JpaMain.java

Parent findParent = em.find(Parent.class, parent.getId());
findParent.getChild().remove(0); // List 컬렉션에서 데이터를 삭제하면서 연관관계 단절
// 0 번째 인덱스, 즉 첫번째 데이터를 삭제한다.

 

그 결과 아래와 같은 hibernate SQL 을 출력하는 것을 볼 수 있다.

- hibernate SQL

Hibernate: // find 메소드로 인한 parent 객체 select
    select
        parent0_.id as id1_7_0_,
        parent0_.name as name2_7_0_ 
    from
        Parent parent0_ 
    where
        parent0_.id=?
Hibernate: // getChildList 메소드로 인한 List select
    select
        childlist0_.parent_id as parent_i3_2_0_,
        childlist0_.id as id1_2_0_,
        childlist0_.id as id1_2_1_,
        childlist0_.name as name2_2_1_,
        childlist0_.parent_id as parent_i3_2_1_ 
    from
        Child childlist0_ 
    where
        childlist0_.parent_id=?
Hibernate: // select 한 컬렉션에서 첫번째 요소에 대한 remove 로 인해 연관관계가 단절되어 고아 객체가 된 child 데이터 삭제
    /* delete hellojpa.Child */ delete 
        from
            Child 
        where
            id=?

 

 

주의할 점?

- CASCADE 와 마찬가지로 참조하는 곳이 하나일 때만 사용해야 한다.(특정 Entity 가 개인 소유일때만 사용 가능하다.)

- 마치 CascadeType.REMOVE 처럼 동작한다.

 

여기서 cascade 옵션을 지우고, 고아 객체 옵션만 남겨준 다음, persist 메소드를 다시 3번 호출해 주고 나서

em.remove(findParent); 처럼 찾아온 부모 객체 자체를 지워버리면 그 아래에 있는 List 에 삽입된 자식 객체의 데이터 까지 모두 지워지게 된다.

(물론 여기서 고아 객체 옵션 없이 그냥 cascade All 에서 위의 코드 em.remove(findParent); 를 사용해도 똑같이 자식 데이터들이 전부 삭제된다.)

- Parent.java

@OneToMany(mappedBy = "parent", orphanRemoval = true)
private List<Child> childList = new ArrayList<>();

- JpaMain.java

Child child1 = new Child();
Child child2 = new Child();

Parent parent = new Parent();
parent.addChild(child1);
parent.addChild(child2);

em.persist(parent);
em.persist(child1);
em.persist(child2);

- hibernate SQL

hibernate SQL
Hibernate: // em.remove(findParent); 로 인해 Parent 밑에 있는 Child 데이터 까지 모두 날아가는걸 볼 수 있다.
    /* delete hellojpa.Child */ delete 
        from
            Child 
        where
            id=?
Hibernate: 
    /* delete hellojpa.Child */ delete 
        from
            Child 
        where
            id=?
Hibernate: 
    /* delete hellojpa.Parent */ delete 
        from
            Parent 
        where
            id=?

 

 

영속성 컨텍스트 + 고아 객체 생명주기

위의 둘을 섞어서 쓰는 것이 가능하다.(CascadeType.ALL + orphanRemoval = true 동시 사용)

- 스스로 생명 주기를 관리하는 Entity 는 em.persist() 로 영속화, em.remove() 로 제거한다.

- 라이프 사이클을 JPA 의 영속성 컨텍스트를 통해서 하는 것이다.(EntityManager 를 통해서)

 

- 그런데 구 옵션을 모두 활성화 하면 부모 Entity 를 통해서 자식의 생명 주기를 관리할 수 있다.

JPA 를 통해서 생명 주기를 관리하는 부모 Entity 와 달리, 자식 Entity 는 부모 Entity 를 통해서 자식의 생명 주기를 관리할 수 있다.

(DB 로 따지면 DAO 나 repository 가 없어도 된다는 뜻)

* 도메인 주도 설계(DDD) 의 Aggregate Root 개념을 구현할 때 유용하다.(지금은 이게 무슨 말인지 잘 모르겠다.)