8. 프록시와 연관관계 관리 (영속성 전이와 고아 객체)

HotFried·2023년 10월 2일
0

영속성 전이: CASCADE

특정 엔티티를 영속 상태로 만들 때 연관된 엔티티도 함께 영속 상태로 만들고 싶을 때 이용

ex) 부모 엔티티를 저장할 때 자식 엔티티도 함께 저장

Parent 엔티티

@Entity
public class Parent {

    @Id @GeneratedValue
    private Long id;

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

    // 양방향 연관 관계를 만들어 주기 위한 편의 메서드
    public void addChild(Child child) {
        childList.add(child);
        child.setParent(this);
    }
}

Child 엔티티

@Entity
public class Child {

    @Id @GeneratedValue
    private Long id;

    @ManyToOne
    @JoinColumn(name = "parent_id")
    private Parent parent;
}

JpaMain

public class JpaMain {

    public static void main(String[] args) {
        Child child1 = new Child();
        Child child2 = new Child();

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

        // 총 3번 persist...번거롭다...
        em.persist(parent);
        em.persist(child1);
        em.persist(child2);

        tx.commit();
    }
}

각각의 Entity를 영속화 해줘야 commit()시점에 쿼리가 3번 날아간다.


Parent가 저장될 때 child도 저장되도록 설정해보자

@Entity
public class Parent {

    @Id @GeneratedValue
    private Long id;

    // cascade 옵션을 주면 영속화가 자식에게도 적용된다.
    @OneToMany(mappedBy = "parent", cascade = CascadeType.ALL)
    private List<Child> childList = new ArrayList<>();

    public void addChild(Child child) {
        childList.add(child);
        child.setParent(this);
    }
}

cascade = CascadeType.ALL어노테이션을 추가하면
부모 저장 시 자식도 모두 저장된다.

주의사항

  • 영속성 전이는 연관 관계를 매핑하는 것과 아무 관련이 없다.
  • Entity를 영속화할 때 연관된 Entity도 함께 영속화 하는 편리함을 제공할 뿐이다.
  • 자식의 부모가 하나일 때, 단일 엔티티에 완전히 종속적이고 라이프 사이클이 같을 때 사용한다.
    ex. 게시판, 첨부파일 경로

종류

  • ALL : 모두 적용
  • PERSIST : 영속
  • REMOVE : 삭제
  • MERGE : 병합
  • REFRESH, DETATCH

-> ALL, PERSIST, MERGE를 가장 많이 이용한다.


고아객체

고아객체 제거

부모 엔티티와 연관관계가 끊어진 자식 엔티티를 자동으로 삭제
orphanRemoval = true 어노테이션 이용

@Entity
public class Parent {

    @Id
    @GeneratedValue
    private Long id;

    // 고아 객체 옵션을 주면 부모가 삭제됐을 때 자식 엔티티를 컬렉션에서 삭제한다.
    @OneToMany(mappedBy = "parent", orphanRemoval = true)
    private List<Child> childList = new ArrayList<>();

    public void addChild(Child child) {
        childList.add(child);
        child.setParent(this);
    }
}
public class JpaMain {

    public static void main(String[] args) {
        Parent parent = em.find(Parent.class, id);
        // 자식 Entity를 컬렉션에서 제거한다. 즉, 연관 관계를 끊는다.
        // 그럼 그 Entity를 삭제한다.
        parent.getChildren().remove(0);

        tx.commit();
    }
}

부모 Entity와 연관 관계가 끊어진 자식 Entity를 자동으로 삭제한다.

Entity의 참조가 제거되면 고아 객체로 판단하고 삭제한다.
-> 연관 관계를 끊었을 때 delete from child where id = ? 쿼리가 자동으로 나감

@OneToOne, @OneToMany만 가능하다.
-> 부모 객체에서 옵션을 설정해야한다는 뜻이다. (One이 부모)


참고 : 개념적으로 부모를 제거하면 자식은 고아가 된다. 따라서 고아 객체 제거 기능을 활성화 하면, 부모를 제거할 때 자식도 함께 제거된다.
이것은 CascadeType.REMOVE처럼 동작한다.


영속성 전이 + 고아객체, 생명주기

  • CascadeType.ALL + orphanRemoval=true

  • 스스로 생명주기를 관리하는 엔티티는 em.persist()로 영속화, em.remove()로 제거

  • 두 옵션을 모두 활성화 하면 부모 엔티티를 통해서 자식의 생명 주기를 관리할 수 있다.

  • 도메인 주도 설계(DDD)의 Aggregate Root개념을 구현할 때 유용하다.


참고 :

김영한. 『자바 ORM 표준 JPA 프로그래밍』. 에이콘, 2015.

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

profile
꾸준하게

0개의 댓글