JPA를 사용하여 Service를 개발하던 중에 특정 Id의 게시글을 조회해서 삭제를 하려고 하였습니다.
기본적인 생각으로는 우선 데이터가 존재하는지 확인 => 삭제 하는 형식이 당연히 맞다고 생각을 하였기에 코드를 아래와 같이 작성했습니다.
@Transactional
public void deleteBoard(int boardId) {
Optional<Board> board = boardRepository.findById(boardId);
if (board.isPresent()) {
boardRepository.deleteById(boardId);
}
}
그런데 코드를 작성하다보니 JPA에는 delete와 deleteById라는 두가지 방법이 있는 걸 발견했습니다. 물론 매개변수는 다릅니다.
delete(Entity)
deleteById(Integer)
하지만 매개변수 차이만으로 불필요하게 하나면 충분한 것을 두가지나 넣을 필요는 없겠죠?
나눠서 확인해보겠습니다.
deleteById
@Override
@Transactional
public void deleteById(ID id) {
Assert.notNull(id, ID_MUST_NOT_BE_NULL);
findById(id).ifPresent(this::delete);
}
findById 를 통해서 조회delete
@Override
@Transactional
@SuppressWarnings("unchecked")
public void delete(T entity) {
Assert.notNull(entity, ENTITY_MUST_NOT_BE_NULL);
if (entityInformation.isNew(entity)) {
return;
}
if (entityManager.contains(entity)) {
entityManager.remove(entity);
return;
}
Class<?> type = ProxyUtils.getUserClass(entity);
// if the entity to be deleted doesn't exist, delete is a NOOP
T existing = (T) entityManager.find(type, entityInformation.getId(entity));
if (existing != null) {
entityManager.remove(entityManager.merge(entity));
}
}
따라서 deleteById를 할 때는 내가 기존에 작성했던 것처럼 findById 검사를 할 필요가 없는 것을 알 수 있습니다.
이럴 고려해서 추가적으로 코드를 작성해보다가 뭔가 이상함을 깨달았습니다.당연히 deleteById를 사용하면 조회가 되고 삭제가 되기에 조회를 했을 때 없으면 Exception이 발생해야하는게 아닌가라는 생각이 들었고 테스트를 해봤다.
boardRepository.deleteById(boardId);
이 코드를 사용해서 테스트를 해봤는데 id가 존재하지 않는 데이터를 삭제하려고 요청을 보내도 Exception이 뜨지 않습니다.
생각해보면 당연한 결과인데, deleteById 내부 코드를 봤을 때 findById로 확인후 존재한다면 delete 메서드를 사용하는 것이기 때문입니다. 그렇다면 findById에는 자동으로 예외처리를 해줄까요?
만약 그랬다면 Optional의 isPresent 메서드를 사용해 확인할 필요가 없을 겁니다.따라서 deleteById 코드를 findById와 delete를 이용해 제가 직접 예외처리를 할 수 있는 코드로 수정했습니다.
다른 좋은 방법도 많겠지만 유동적으로 예외처리를 할 수 있다는 점에서 택했습니다.
코드는 아래와 같습니다.
public void deleteBoard(Integer boardId) throws Exception {
Optional<Board> board = boardRepository.findById(boardId);
if (board.isPresent()) {
boardRepository.deleteById(board.get());
} else {
throw new Exception("Id Null Exception");
}
}