인프런 영문 브랜드 로고
인프런 영문 브랜드 로고

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

이지창님의 프로필 이미지

작성한 질문수

호돌맨의 요절복통 개발쇼 (SpringBoot, Vue.JS, AWS)

다중 데이터를 삭제 할 때

해결된 질문

작성

·

69

·

수정됨

0

안녕하세요.

호돌맨님 인강 들으면서 어찌저찌 취업하게 된 신입 개발자입니다.

 

현재 postDelete 로 단일 데이터를 검증 후 삭제하고있는데,

만약 List로 된 다중 PK 를 검증하고 삭제할 때는 어느 방법이 좋은건지 잘 모르겠습니다.

 

public void postAllDelete(List<Long> postIds) {
    //1번
    List<Post> posts = postRepository.findAllById(postIds);
    if(posts.isEmpty()) throw new IllegalArgumentException("삭제할 게시글이 존재하지 않습니다.");
    postRepository.deleteAll(posts);
    
    //2번
    postIds.forEach(e-> {
        Post post = postRepository.findById(e)
            .orElseThrow(PostNotFound::new);
        postRepository.delete(post);
    });
    
}

 

1번 같은 경우는 조회 및 삭제 각 한번씩 DB 를 호출해서 성능적으로 좋다고 생각하는데,

리스트에 담겨져있는 PK 가 유효한지 검증하려면 stream API 를 사용하여 map 으로 PK 추출 후 filter 로 검증을 하는게 좋은건지, 혹은 다른 방법이 있는지 궁금합니다

 

물론 현재는 데이터가 많이 없으니 어느 방법을 채택해도 상관없지만

추후에 대량의 데이터를 접하게될 때를 생각하다보니,,

 

 

어떻게 보면 인강과 관련없는 질문이긴한데,,

염치 불구하고 도움 주시면 감사하겠습니다.

답변 2

0

호돌맨님의 프로필 이미지
호돌맨
지식공유자

안녕하세요. 호돌맨입니다.

질문 감사합니다.

여러개의 id를 기반으로 entity를 삭제할때 질문이시군요

그런데 보내주신 코드를 보아하니.. 우리는 먼저 이런 부분을 생각 해야합니다.

 

여러개를 한 번에 조회하고 한번에 삭제하는 경우

클라이언트가 서버로 1부터 100까지 (1,2,3,4,5...100) 총 100개의 id를 던지며 삭제하기를 희망한다고 해봅시다.

그런데 만약 id=55의 게시글이 존재하지 않는다면 어떨까요?. 클라이언트 버그로 존재하지 않는 id를 요청 한 걸수도 있고 이미 삭제된 게시글 일수도 있겠죠. 그런 상황에서 1번 케이스는 클라이언트에게 적당히 오류를 뱉어줄 방법이 없습니다. 100개의 게시글이 아닌 99개의 글을 삭제한 건 클라이언트가 기대한 부분이 아니기 때문에 적당히 예외 처리를 해야할 것 같습니다.

하지만 클라이언트에게 그런 오류를 응답하는게 맞을까요? 이거는 삭제하는 대상, 목적 등에 따라 다릅니다.

클라이언트 입장에서는 요청시 "id 100개 던질테니 꼭 모두다 삭제 해야되고, 1개라도 실패하는 케이스가 있으면 안돼"를 기대할수도 있고 "id 100개 던질테니 삭제 되던가 말던가 알아서 해"일수도 있겠죠.

그렇기 때문에 클라이언트 개발자와 이야기를 나누고 삭제 처리의 목적 등을 우선 생각해 볼 필요가 있습니다.

"100개가 모두다 삭제 되어야 해?, 만약 1개라도 삭제가 안되면 어떻게 할까? 오류 메시지를 줄까? 아니면 99개는 삭제되지 않은 1개에 대해서만 응답리스트에 담아 줄까?"

 

제가 가정하는 상황에서 id 100개 조회 성능은 크게 상관없을것 같습니다.
그러면 아래 느낌의 코드를 만들 수 있겠죠.

public void postAllDelete(List<Long> postIds) {
    List<Post> posts = postRepository.findAllById(postIds);

    var notExistsIds = [];
    if (postIds.size() != posts.size()) { // 검사 후 에러
        notExistsIds = 요청했지만 존재하지 entity의 id 얻기();
    }
    
    postRepository.deleteAll(posts);

    return notExistsIds
}

 

Soft Delete 케이스

실제 entity를 삭제하지 않고 deleted column을 둔 뒤에 soft delete하는 상황도 생각 해보셔야합니다.

 

데이터가 많은경우

100개 정도는 상관 없겠지만, 삭제하는 데이터가 정말정말 많은 경우는 배치 처리를 고려하셔야 할 수 있습니다.

 

감사합니다.

0

인프런 AI 인턴님의 프로필 이미지

안녕하세요, 인프런 AI 인턴입니다.
이지창님, 질문 감사합니다.

다중 데이터를 삭제하는 경우, 성능과 데이터 일관성을 고려하여 적절한 방법을 선택하는 것이 중요합니다.

1번 방법은 findAllById로 조회한 후, deleteAll을 통해 한 번에 삭제하기 때문에 성능상 이점이 있지만, 유효성 검증은 별도로 적용하지 않는다면 리스트 내의 전체 유효성을 보장하지는 않습니다. 전체 post들이 존재하지 않을 때 예외 처리만 되고, 부분적으로 유효하지 않은 ID에 대한 처리가 되지 않습니다.

2번 방법은 각각의 ID를 개별적으로 검증하여 처리하기 때문에 데이터 정확성 확보 측면에서는 용이하지만, 비효율적인 다수의 DB 호출이 발생할 수 있습니다.

만약 대량의 데이터 유효성 검증과 삭제를 동시에 하려면 다음과 같은 접근을 고려해볼 수 있습니다:

public void postAllDelete(List<Long> postIds) {
    List<Post> posts = postRepository.findAllById(postIds);
    
    if(posts.size() != postIds.size()) {
        Set<Long> foundIds = posts.stream()
                                  .map(Post::getId)
                                  .collect(Collectors.toSet());
        List<Long> missingIds = postIds.stream()
                                       .filter(id -> !foundIds.contains(id))
                                       .collect(Collectors.toList());
        throw new IllegalArgumentException("삭제할 게시글이 존재하지 않습니다: " + missingIds);
    }

    postRepository.deleteAll(posts);
}

위 방법에서는 모든 ID를 일괄 조회한 후, 조회된 결과의 ID 리스트와 입력된 ID 리스트를 비교하여 누락된 ID가 있을 경우 이를 추적하고 예외를 발생시키는 방법입니다.

이렇게 하면 각 ID가 유효한지 검증하면서도, 데이터베이스와의 통신 횟수를 최소화할 수 있습니다.

추후 데이터량이 많아질 경우, 조회와 삭제 모두 batch 처리(한번에 일정량씩 처리)로 변경하는 것을 고려할 수도 있습니다. 성능과 효율을 최대화하기 위해서는 실제 비즈니스 요구 사항에 따라 유연하게 선택해야 합니다.

더 궁금한 사항이 있으면 언제든지 질문해 주세요. 감사합니다!

관련 자료: Spring Data JPA - Reference Documentation