
안녕하세요!🙂😊
오늘은 JPA 중에서도 orphanRemoval 옵션에 대해서 집중적으로 알아보려합니다.
orphanRemoval = true는 JPA에서 부모 엔티티와 연관이 끊어진(고아가 된) 자식 엔티티를 자동으로 삭제해주는 옵션입니다.
편리하지만 잘못 사용하면 예상치 못한 삭제가 발생할 수 있는데요.
이것을 이해하려면 실수할 수 있는 대표적인 사례와 함께 작동 원리를 올바르게 이해할 필요가 있습니다.
참고로, 본 내용에서 다루는 Hibernate 버전은 5.x 입니다.
예상치 못한 삭제 발생
성능 문제
다음과 같이 Child 엔티티에 다음과 같이 @SQLDelete와 @Where를 설정했다고 가정합니다.
@Entity
@SQLDelete(sql = "UPDATE child SET is_deleted = true WHERE id = ?")
@Where(clause = "is_deleted = false")
public class Child {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
private boolean isDeleted = false;
@ManyToOne
private Parent parent;
// Getters and Setters
}
그리고 Parent 엔티티를 구현하여 Child 엔티티와 연관관계를 설정합니다.
@Entity
public class Parent {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
@OneToMany(mappedBy = "parent", cascade = CascadeType.REMOVE, orphanRemoval = true)
private List<Child> children = new ArrayList<>();
public void addChild(Child child) {
child.setParent(this);
this.children.add(child);
}
public void removeChild(Child child) {
this.children.remove(child);
child.setParent(null);
}
}
Parent 와 Child 엔티티를 다음과 같이 처리합니다.
// Parent와 Child를 저장
Parent parent = new Parent();
parent.setName("Parent 1");
Child child1 = new Child();
child1.setName("Child 1");
parent.addChild(child1);
em.persist(parent);
em.flush(); // DB에 저장
// Parent에서 Child 제거
parent.removeChild(child1); // 고아로 간주됨
em.flush(); // orphanRemoval로 인해 Child 삭제 트리거
동작 분석을 해보면 다음과 같습니다.
parent.removeChild(child1);
em.flush();
만약 @SQLDelete 를 통해 Soft Delete(UPDATE 쿼리)를 설정했음에도 불구하고 Hard Delete 가 발생했다면?