Jpa와 Hibernate는 데이터베이스의 데이터를 객체로 다룰 때 사용되는 도구이다.
여기서 '엔터티'라는 단어는 그런 데이터를 나타내는 객체를 말합니다.
이 객체들 사이에는 '연관 관계'라는 관계가 있을 수 있다.
예를 들면 부모와 자식처럼
이때 자식 엔터티가 'orphan'이라는 상태, 즉 부모와의 연결이 끊긴 상태가 되었을때 Orphan removal이 활성화 되어 있으면 Jpa와 Hibernate는 이런 'orphan' 자식 엔터티를 데이터베이스에서 자동으로 삭제해준다.
코드에서 user 객체에는 후라이드 치킨이 제거 되었지만 DB에는 여전히 존재한다.
Orphan을 사용시 DB까지 한번에 지워진다.
"orphan removal"은 JPA에서 제공하는 기능으로, 엔터티 간의 연관 관계에서 자식 엔터티가 부모 엔터티와의 연관 관계에서 제거될 때 자동으로 삭제하는 기능이다. 이 기능은 주로 @OneToMany
와 @OneToOne
의 비주인 측에서 설정된다.
Parent
엔터티와 Child
엔터티 간의 관계는 아래와 같다
@Entity
public class Parent {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@OneToMany(mappedBy = "parent", cascade = CascadeType.ALL, orphanRemoval = true)
private List<Child> children = new ArrayList<>();
// getter, setter, etc.
}
@Entity
public class Child {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@ManyToOne
private Parent parent;
// getter, setter, etc.
}
여기서 orphanRemoval = true
로 설정하면, Parent
엔터티의 children
컬렉션에서 Child
엔터티를 제거할 때 해당 Child
엔터티도 데이터베이스에서 자동으로 삭제된다.
Parent parent = entityManager.find(Parent.class, parentId);
Child child = entityManager.find(Child.class, childId);
parent.getChildren().remove(child);
entityManager.persist(parent); // 이 시점에서 orphan removal이 동작하며, child 엔터티가 데이터베이스에서 삭제된다.
의도하지 않은 삭제
Orphan removal이 활성화된 컬렉션에서 엔터티를 제거하면 해당 엔터티는 데이터베이스에서도 자동으로 삭제된다.
성능 문제
큰 컬렉션에서 Orphan removal을 사용하면 성능 이슈가 발생할 수 있다. 예를 들어 큰 컬렉션에서 몇 개의 항목만을 제거하려고 할 때 JPA는 먼저 전체 컬렉션을 데이터베이스에서 삭제한 다음 유지하려는 항목들만 다시 추가하는 방식으로 동작할 수 있습니다. 이러한 동작 방식은 많은 SQL 작업을 발생시켜 성능을 저하시킬 수 있습니다.
불필요한 복잡성
Orphan removal이 항상 필요하지는 않다. 때로는 단순히 연관관계를 끊고 싶을 뿐, 실제 엔터티를 삭제하고 싶지 않은 경우가 있을 수 있다. 이 경우 Orphan removal의 동작이 불필요한 복잡성을 추가할 수 있다.
재사용 문제
Orphan removal이 활성화된 자식 엔터티를 다른 부모에 연결하려고 할 때 문제가 발생할 수 있다. 이전 부모와의 연결이 끊어지면서 자식 엔터티가 삭제되어버리기 때문이다. 이 문제를 피하려면 자식 엔터티를 새 부모에 연결하기 전에 이전 부모와의 연결을 명시적으로 끊어야 한다.
트랜잭션 경계: Orphan removal 동작은 트랜잭션 경계 내에서 발생한다. 따라서 트랜잭션을 커밋하기 전에는 실제 데이터베이스에서 삭제되지 않는다. 이 점을 인식하지 못하면 혼동을 초래할 수 있다.