jpa 영속성 전이 cascase와 고아 객체 orphan
영속성을 한 번에 관리한다. 영속성 전이 cascade
- 기본적으로 영속성은 아래와 같이 관리한다.
@Entity
@Setter
@Getter
public class Parent {
@Id
@GeneratedValue
private Long id;
private String name;
@OneToMany(mappedBy = "parent")
private List<Child> children = new ArrayList<>();
public void addChild(Child child){
children.add(child);
child.setParent(this);
}
}
@Entity
@Setter
@Getter
public class Child {
@Id
@GeneratedValue
private Long id;
private String name;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "PARENT_ID")
private Parent parent;
}
Child child1 = new Child();
Child child2 = new Child();
child1.setName("chi1");
child2.setName("chi2");
Parent parent = new Parent();
parent.addChild(child1);
parent.addChild(child2);
em.persist(parent);
em.persist(child1);
em.persist(child2);
- 위의 메서드를 수행하면 insert 쿼리가 세 번 나간다. 만약 Parent 엔티티의 값을 아래와 바꾸면, 영속성을 주인 객체 하나만 수행하면 대상 객체는 자동으로 수행된다.
public class Parent {
// ...중략...
@OneToMany(mappedBy = "parent", cascade = CascadeType.ALL)
private List<Child> children = new ArrayList<>();
// ...중략...
}
em.persist(parent);
// em.persist(child1);
// em.persist(child2);
- 이는 프록시나 연관관계 맵핑 등 다른 기법과 전혀 관계 없다.
cascade의 옵션
- ALL, PERSIST, REMOVE 등 주로 사용한다.
- 사용할 때의 팁은,
- 부모가 자식을 완전하게 관리하는 경우만 사용한다. 자식이 다른 객체와 연관관계를 가질 경우 절대로 사용해서는 안된다.
- 라이브사이클이 거의 일치할 때만 사용한다.
고아 객체, 영속성이 끊어진 데이터를 자동 삭제한다. orphanRemoval
@OneToMany(mappedBy = "parent", cascade = CascadeType.PERSIST, orphanRemoval = true)
private List<Child> children = new ArrayList<>();
Child child1 = new Child();
Child child2 = new Child();
child1.setName("chi1");
child2.setName("chi2");
Parent parent = new Parent();
parent.addChild(child1);
parent.addChild(child2);
em.persist(parent);
em.flush();
em.clear();
final Parent findParent = em.find(Parent.class, parent.getId());
em.remove(findParent);
tx.commit();
Hibernate:
/* delete jpa6_proxy.e_orphan.Child */ delete
from
Child
where
id=?
Hibernate:
/* delete jpa6_proxy.e_orphan.Child */ delete
from
Child
where
id=?
Hibernate:
/* delete jpa6_proxy.e_orphan.Parent */ delete
from
Parent
where
id=?
- 참조(부모 객체)가 사라진 경우, 고아 객체로 보고 삭제한다. cascade의 REMOVAL 혹은 ALL과 동일하게 동작한다.
- 위의 코드는 영속성 전이를 persist로만 한다. 고아 객체 삭제를 없앨 경우, fk 제약조건으로 인하여 부모 객체의 삭제가 정상 진행되지 않는다.
ERROR: Referential integrity constraint violation: "FKQTRFKXTU92RLLEPI09F1MWVLS: PUBLIC.CHILD FOREIGN KEY(PARENT_ID) REFERENCES PUBLIC.PARENT(ID) (1)";
- 영속성 전이와 동일한 위험성을 가진다.
자식의 생명주기
- 영속성 전이와 고아 객체를 통해 자식의 생명주기를 부모의 생명주기를 통제할 수 있다.
- 도메인주도설계(DDD)의 Aggregate Root 개념을 구현할 때 유용하다. 자식에 대한 DAO나 Repository가 필요로 하지 않는다.