본문 바로가기

Spring

항해 99 실전 프로젝트 - CRUD

 금일 프로젝트 중 생긴 트러블

1. 문제가 생길 만큼 너무 느린 성능의 삭제 프로세스 

public MsgResponse deleteQuiz(Long id) {
    //이전의 것과 마찬가지 입니다.
    Quiz quiz = findQuiz(id);
    List<Comment> comments = getComment(id);
    List<QuizQuestion> quizQuestionList = quizQuestionRepository.findAllByQuiz(quiz);
    List<QuizChoices> quizChoicesList = new ArrayList<>();
    for (QuizQuestion quizQuestion : quizQuestionList) {
        List<QuizChoices> quizChoices = quizChoicesRepository.findAllByQuizQuestion(quizQuestion);
        quizChoicesList.addAll(quizChoices);
    }
    // 여기도 마찬가지로 효율이 좋다고하네요? (테스트 결과 문제수 22개, 문항 수 44개 before 1199ms | after 139 ms)
    commentRepository.deleteAllInBatch(comments);
    quizChoicesRepository.deleteAllInBatch(quizChoicesList);
    quizQuestionRepository.deleteAllInBatch(quizQuestionList);
    quizRepository.delete(quiz);

    return new MsgResponse("퀴즈 삭제 성공! ");
}

 현재, DB의 연관관계는 Many To One 으로 모두 m쪽에서 key를 관리하고 있다. 양방향으로 연관관계를 설정하는 것을   기피했기 때문에 삭제를 위해서는 일일이 다 찾아야 하는 조회하여 발견해야 하는 성능의 저하가 발생하였음 

repository.deleteAll() -> before
repository.deleteAllInBatch() -> after

Before : 해당 퀴즈에 문제 22개 작성 + 선택지 44개 작성 후 삭제시 1199ms의 저성능을 보여줌 

after : 해당 퀴즈에 문제 22개 작성 + 선택지 44개 작성 후 삭제시 139ms의 개선된 성능을 보여줌 

*약 1/9로 삭제 성능을 개선함 

다른 대안으로 DB의 연관관계를 바꾼 후 cascade를 통해 영속성 전이를 활용해 삭제를 해볼까? 라는 생각을 잠시 하였지만,  db의 관계를 손보는 것에서 개인적으로 하나의 테이블에 너무 많은 값을 주는거 같다는 생각이 들어 기피한 것과 

 cascade는 굉장히 유용한 에노테이션이지만, 반대로 너무 유용해서 내가 고려하지 못한 부분도 지울 수 있다는 생각에 확실하게 찾아서 삭제하는 것으로 결정하였다. 그러나 실제 서버를 운영하면서 너무 많은 시간이 소요된다고 하면 이를 인식하고 cascade로 변경하려고 함 

 

2.  무한 재귀현상 

 프로젝트 api 개발 중, 조회하여야 할 Repository에서 findBy로 찾아야 할 것들이 있었다. 그러는 중 key값(외래키)을 가진 entity와 키의 entity를 조회하는 상황이 발생하였다. 그로 인하여 무한재귀 현상이 발생하였다. 

 * 해결방안 

@ManyToOne
@JsonIgnore // 조회를 하려는 중에 무한 재귀 현상 발생 -> 그로 인하여 Ignore을 활용하여 조회를 방지하는 해결
@JoinColumn(name = "quiz_question_id",nullable = false)
private QuizQuestion quizQuestion;

 JsonIgnore을 통하여 그냥 조회를 막는 것으로 해결하였다. 

 만약 직접적으로 조회하는 것이 필요하다면 키를 One에게 주는 것으로 해결할 예정이였으나 현재 상황에서 추가적으로 연관성을 가지는 것 이외의 Key를 활용하는 이유가 없기 때문에 JsonIgnore를 통해서 데이터를 조회할 때 조회하는 것을 방지하는 것으로 결정하였다. 

 

3.  PathVariable 사용 미숙 

@GetMapping("/quiz/{id}/quizQuestion/{questionNum}")
public ResponseEntity<ShowQuestionResponseDto> showQuizQuestion (@PathVariable Long id,
                                                                 @PathVariable Integer questionNum){
    return ResponseEntity.ok(quizQuestionService.showQuizQuestion(id, questionNum));
}

 이와 같은 컨트롤러에서 @PathVariable을 붙이고 , 뒤에도 적용 가능한 것으로 생각해 했다가 null로 반환하는 것을 확인 

 때문에 2개다 작성해주는 것으로 해결