인프런 커뮤니티 질문&답변

Backend.dev님의 프로필 이미지

작성한 질문수

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

영속성 전이(CASCADE)와 고아 객체

JPA에서의 올바른 엔티티 삭제 방법에 대해 질문 드립니다.

21.03.30 13:11 작성

·

1.7K

2

영한님 안녕하세요 :)

오래전에 공부 했던게 기억나지 않아서 예전에 봤던 강의를 돌고 돌다가 질문을 남기게 되었습니다.

UPDATE는 더티체킹으로 변경하는 것에 대해서는 이해하고 적용을 하고 있는데, 효율적인 삭제 방법에 대해서는 감이 잡히지 않아서 이렇게 질문을 드립니다.

아래와 같은 간단한 상황을 예를 들면서 질문을 드리겠습니다.

위와 같은 도메인들이 있고, 각각은 모두 양방향 참조를 하고 있는 상황이라 가정 하겠습니다.

이 때 비즈니스 요구사항은 아래와 같습니다.

1. MEMBER 탈퇴 시에 해당 MEMBER에 연관된 POST도 모두 함께 삭제 되어야 한다.

2. 특정 CATEGORY 삭제 시 해당되는 POST는 남겨두고 CATEGORY만 삭제가 되어야 한다.

1번, 2번이 서로 조건이 상반 되는데요. 여기서 질문을 드리고 싶습니다.

질문 1) 1번 요구사항의 경우 orphanRemoval 혹은 Cascade를 통해 손쉽게 할 수 있을거 같습니다.

Cascade를 적용 해놓았기 때문에 JpaRepository의 delete 메서드로 MEMBER를 지우면 해당되는 POST도 모두 지워질 듯 한데요.

이런 요구사항에서는 이렇게 지우는게 best practice가 맞는지 알고 싶습니다.

질문 2) Cascade All, orphanRemoval을 함께 사용하면 부모 엔티티와 자식 엔티티가 생명 주기를 함께 하면서 부모 엔티티가 자식 엔티티에 대한 모든 제어권을 가지는 것과 마찬가지라고 알고 있습니다.

그런데 앞선 질문1 처럼 삭제 할 때만 Cascade를 적용하고 싶다면 Cascade DELETE가 더 적합할 듯 한데요. 강의에서 DELETE는 많이 안쓴다고 언급 하셨습니다. DELETE를 잘 사용하지 않는 어떤 이유가 있는지 궁금 합니다!

질문 3) 위 요구사항에 의하면 MEMBER와는 다르게 CATEGORY는 부모 엔티티가 삭제 되어도 자식 엔티티인 POST를 그대로 남겨두어야 합니다.

이 때,  CATEGORY의 POST List를 순회하면서 해당 POST에서 CATEGORY 와의 관계를 끊어주어야 할 듯 한데요.

 반복문 또는 stream을 사용하면서 모든 관계를 끊어주어야 한다고 할 때, 성능상에 문제가 생기지는 않는지 궁금합니다.

예를 들어 CATEGORY가 10만개, 100만개의 POST와 연관관계를 가지고 있었다면, 이때는 어떤 방법으로 처리 하는지 알고 싶습니다. (JPQL로 직접 쿼리를 날리는 방법이 가장 먼저 떠오르는데, 무언가 JPA스러운(?) 우아한 방법이 있을거 같네요ㅎㅎ)

질문 4) 자식 엔티티를 가지지 않는 POST 엔티티를 삭제 할 때는

1. PostRepository의 delete를 직접 사용해서 지운다.

2. CATEGORY, MEMBER와의 관계를 null 처리 하고, 두 부모 엔티티 리스트에서 해당 POST를 지운다.

두 방법 모두 가능 가능할 듯 한데요. 

어떻게 삭제를 하는 것이 best practice인지 알고 싶습니다.

(+) 내용이 읽기 불편하실거 같아 개행을 많이 했는데도 게시판에 적용이 안되는 듯 하네요. 양해 부탁 드립니다ㅠㅠ

감사합니다.

답변 1

1

김영한님의 프로필 이미지
김영한
지식공유자

2021. 03. 30. 20:27

안녕하세요. Backend.dev님 고민이 여기까지 느껴지네요^^

처음 JPA를 설계한다면 cascade, orphanRemovel은 생각하지 않고 개발하는 것을 추천합니다.

cascade, orphanRemovel은 회원 -> 회원상세처럼 완전히 개인 소유가 가능할 때 사용하는 옵션입니다.

MEMBER, POST, CATEGORY는 모두 각각 의미있는 개별 엔티티입니다. 따라서 어디에 소속되도로 설계하는 것은 좋지 않습니다.

각각 별도의 Repository를 사용하시고, cascade, orphanRemoval은 사용하지 않는 것이 좋습니다.

질문1, 질문2를 함께 답변을 드릴게요.

실무에서는 실제 데이터를 삭제하는 경우가 드뭅니다. 데이터를 이동해두거나 또는 삭제여부 필드를 추가하는 방식으로 문제를 해결합니다.

왜냐하면 데이터가 삭제되면 복구가 어렵기 때문이지요. 실수로 삭제될 수도 있구요. 삭제된 내용을 확인해야 하는 경우도 많습니다.

그래서 DELETE 자체에 대해서 고민해보아야 합니다.

질문3, 질문4

PostRepository에 해당 카테고리에 소속된 Post를 삭제하는 delete 쿼리를 날리면 되겠지요?

감사합니다.