개념 Self Study📝/Java
Spring Boot JPA Update 방법은 다양하다?
코딩 욕심쟁이
2023. 4. 27. 02:32
1.개요
- Final Project를 진행하는 도중 C,U,D기능에서 U기능이 에러(NullPointExceptionError)가 발생하였다. 그 이유로는 게시물에 대해서 삽입해야하는 값들이 많은데 값 삽입 도중 원치 않는값들을 입력하지 않으면 자체적으로 null값으로 넘김에 따라서 에러가 발생하였다.
- 문제 풀이 서비스를 만들었는데 문제 풀이 특성상 객관식,주관식 구분하면 조건도 달라 에러(NullPointExceptionError)가 자주발생 하여 다른 방법의 Update JPA를 모색하였다.
2. Update 방법의 다양성
- Builder를 통한 Update
- Builder패턴을 이용하여 build를 한 후 기존에 있던 엔티티를 조회한 후 조회한 Entity에 JPA의 save메서드를 이용하여 기존에 있던 정보에 DTO를 통해 주입하여 새로운 값을 덮어씌우는 방법
public Problem updateProblem(Long problemId, Problem updatedProblemData) {
// Find the problem using problemId
Optional<Problem> problemOptional = problemRepository.findById(problemId);
if (!problemOptional.isPresent()) {
throw new NoSuchElementException("Problem not found");
}
Problem existingProblem = problemOptional.get();
// Update existingProblem with updatedProblemData using Builder pattern
Problem updatedProblem = Problem.builder()
.id(existingProblem.getId())
.title(updatedProblemData.getTitle())
.description(updatedProblemData.getDescription())
.build();
// Save the updated problem
return problemRepository.save(updatedProblem);
}
-> 해당 방법으로 save메서드를 이용할수 있다
- Setter를 통한 Update
- 위 방법과 같이 save메서드를 이용하는 Update방법으로 하나이다.
- Setter를 사용하면 의도가 불분명하고 변경하면 안되는 중요한 값 임에도 불구하고 변경한 값으로 착각할수 있어서 안정성이 보장이 안되기도 한다고 한다.
public Problem updateProblem(Long problemId, Problem updatedProblemData) {
// Find the problem using problemId
Optional<Problem> problemOptional = problemRepository.findById(problemId);
if (!problemOptional.isPresent()) {
throw new NoSuchElementException("Problem not found");
}
Problem existingProblem = problemOptional.get();
// Update existingProblem with updatedProblemData using setters
existingProblem.setTitle(updatedProblemData.getTitle());
existingProblem.setDescription(updatedProblemData.getDescription());
// Save the updated problem
return problemRepository.save(existingProblem);
}
- DirtyChecking을 이용한 Update
- 위 방법과 같이 기존의 Id를 조회한 후 조회한 Id에 Entity에 정의한 메서드를 서비스에서 정의한 후 DTO를 삽입하는 방식으로 사용하면 된다.
- 해당 방법으로 save를한다면 변경이 감지되어 변경되는 값만 인식하여 값을 업데이트 해준다.
1) 다음과 같이 엔티티에 메서드를 정의한 후
public void updateProblem(ProblemUpdateRequestDto updateRequestDto) {
this.title = updateRequestDto.getTitle();
this.content = updateRequestDto.getContent();
this.answer = updateRequestDto.getAnswer();
this.level = updateRequestDto.getLevel();
this.writer = updateRequestDto.getWriter();
this.hashtag = updateRequestDto.getHashTag();
this.type = updateRequestDto.getType();
}
2) Service에 다음과 같이 사용할수 있다.
public ProblemUpdateResponseDto update(ProblemUpdateRequestDto updateRequestDto) {
//수정 권한 확인
Optional<String> problem1 = Optional.of(problemRepository.UpdateLicense(updateRequestDto.getProblemId()));
problem1.orElseThrow(AccessException::new);
//데이터 존재여부확인
Problem problem = problemRepository.findById(updateRequestDto.getProblemId()).orElseThrow(NullPointerException::new);
problem.updateProblem(updateRequestDto);
problemRepository.save(problem);
return ProblemUpdateResponseDto.builder()
.code(String.valueOf(HttpStatus.OK))
.msg("수정이 완료되었습니다.")
.build();
}
3. 위 방법들의 차이점
- Setter
- 가장 간단하고 직관적인 방법
- 새로운 필드가 추가되거나 수정될때 마다 Setter메서드를 사용해야한다.
- 필드가 많아지면 코드가 길어지고, 관리하기 어려워진다.
- 객체의 불변성 유지 불가
- Builder패턴
- 엔티티 클래스를 수정하는 대신,Builder클래스를 사용하여 변경사항을 관리한다.
- 코드가 깔끔하며, 새로운 필드가 추가되거나 수정되더라도 Builder클래스만 변경하면 된다.
- 객체의 불변성 유지 가능
- Dirty Checking을 이용한 업데이트
- JPA의 내장 기능을 활용하는 방법이다.
- 트랜잭션 내에서 엔티티를 조회하고 변경하면, 트랜잭션이 종료되는 시점에 변경된 엔티티가 자동으로 저장된다.
- 변경감지를 통해 변경된 필드만 데이터베이스에 반영되므로, 성능이 향상 된다.
- 객체의 불변성을 보장하지 않으며, 코드가 다소 불명확해질수 있다.
4. 결론
-해당 프로젝트를 경험하며 null값이 많이 들어갈 경우에는 변경감지 방법인 DirtyChecking 방법을 사용하게 되면 성능이 향상 되는것을 알게되어 개인적으로는 DirtyChecking방법을 자주 이용할거 같다.