JPA/JPA 기본

29. 영속성 전이와 고아 객체

sdafdq 2023. 10. 28. 19:29

영속성(persist) 전이는

말 그대로 특정 엔티티 persist 하면 연관된 엔티티들도 persist 하는

말 그대로 영속성을 전이시키는 거임.

그러니까, Member에 필드로 Team이 있으면,

이 영속성 전이 기능을 사용하면 member만 persist 해도 Team도 persist 되는거임.

 

코드

@Entity
public class Parent {
    @Id @GeneratedValue
    private Long id;
    private String name;

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

간단하다.

그냥 같이 persist 하고 싶은 연관관계에

cascade = CascadeType.ALL

이라고 하면 된다.

그러면

 

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

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

em.persist(parent);

tx.commit();

이렇게 parent만 persist 해도 CascadeType.ALL 지정한 child 들도 알아서 insert 쿼리가 나간다.

저걸 연관관계 주인에 할지, 노예에 할 지는 프로젝트에 따라? 인거 같다.

Parent 위주로 관리하고 싶다면 저렇게..

 

CascadeType은 

ALL : 모두적용

PERSIST : 영속

REMOVE : 삭제

MERGE : 병합

REFRESH : REFRESH

DETACH : DETACH

이렇게 6가지 있는데,

ALL, PERSIST만 쓴다.

 

ALL은 모든 생명주기를 따라가게 하는 거고,

PERSIST는 persist 할 때만 맞추는 거.

ALL 하면 예를 들어 저거 지우면 같이 지워지는..

또 조회할 때 알아서 같이 가져옴.

 

ALL하면 persist 뿐만 아니라 조회, 삭제도 같이 됨.

 

REMOVE는 삭제할 때만 따라간다. 부모객체가 삭제되면 저것도 같이 삭제됨.

cascade는 부모 따라 간다고 생각하면 됨.

cascade 자체가 직역이 종속.

 

 

주의할 것이,

서로 뭐랄까 딱 Perent만 child를 관리하면 모르겠는데, (즉, child의 소유자가 하나일 때)

child를 여러 군데서 관리하면 쓰면 안된다.

 

즉, 엔티티가 완전히 종속적일 때만 사용해야 한다.

 

라이프 사이클이 같을 때,

child의 소유자가 하나일 때만 써야 한다.

 

예를 들면 게시판의 글과, 첨부파일같이?

 

 

고아객체

고아 객체는 부모와 연관관계가 끊어직 자식 엔티티,

그러니까 객체상에서 부모와 연이 끊어진 자식 객체를 실제로 DB에서 삭제시킬 수 있다.

 

예를 들어,

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

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

em.persist(parent);

em.flush();
em.clear();

Parent findParent = em.find(Parent.class, parent.getId());
findParent.getChildren().remove(0);

tx.commit();

저렇게 객체상에서 삭제 해 봤자 사실 삭제가 안된다. 그런데,

@Entity
public class Parent {
    @Id @GeneratedValue
    private Long id;
    private String name;

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

이렇게 

orphanRemoval(고아 제거)를 true로 하면,

위에 처럼 list에서 객체 상에서 지운 것도 반영이 되어

delete 쿼리가 나간다.

 

즉, 참조가 제거된 엔티티는 고아객체로 보고 DB상에서도 실제 삭제한다.

 

이것 또한 참조하는 것이 하나일 때, child의 소유자가 하나일 때, 완전히 종속적일 때 써야 한다.

 

특정 엔티티가 완전히 개인소유일 때.

 

또, 당연히 부모가 사라지면, 

Child는 고아가 되므로 그것도 삭제된다.

 

 

@Entity
public class Parent {
    @Id @GeneratedValue
    private Long id;
    private String name;

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

이렇게 cascade, orphanRemoval을 모두 저렇게 설정해 주면,

부모 객체에서 자식을 완전히 관리할 수 있게된다.

cascade를 ALL로 해놔서 부모 따라가고,

orphanRemoval 고아 제거를 true로 해 놔서, 

Parent객체에서 children 중 하나를 지워버리면 그 child는 부모없는 고아가 되는 거니까 고아제거 설정덕에 DB에서도 지워진다.

 

 

'JPA > JPA 기본' 카테고리의 다른 글

31. 기본값 타입  (0) 2023.10.29
30. 실전 연관관계 관리  (0) 2023.10.29
28. 즉시로딩, 지연로딩  (0) 2023.10.28
27. 프록시  (0) 2023.10.27
25. Mapped Superclass 매핑 정보 상속  (0) 2023.10.27