2022-07-08-TIL
Today I Learned
JPA delete vs deleteById
Spring Data JPA의 delete(entity)와 deleteById(id)는 둘 다 엔티티를 지우지만, 대상이 없을 때 동작이 다르다. 구현은 SimpleJpaRepository에 있다. 아래는 2.7.0 태그 기준 소스다.
1
2
3
4
5
public void deleteById(ID id) {
Assert.notNull(id, ID_MUST_NOT_BE_NULL);
delete(findById(id).orElseThrow(() -> new EmptyResultDataAccessException(
String.format("No %s entity with id %s exists!", entityInformation.getJavaType(), id), 1)));
}
deleteById는 먼저findById로 엔티티를 조회한다. 없으면EmptyResultDataAccessException을 던지고, 있으면delete(entity)를 호출한다.delete(entity)는 엔티티가 새것이면 아무것도 하지 않는다. 아니면em.find로 DB에 있는지 확인하고, 없으면 조용히 끝낸다(소스 주석의 표현으로 “NOOP”). 있으면em.remove를 호출한다.
즉 deleteById로 없는 id를 지우면 예외가 나고, delete로 없는 엔티티를 지우면 아무 일도 일어나지 않는다. 그리고 두 방법 모두 바로 DELETE 쿼리를 보내지 않고 먼저 SELECT로 엔티티를 영속성 컨텍스트에 올린 뒤 지운다. 엔티티의 생명주기 콜백(@PreRemove)과 cascade 설정이 적용되도록 하기 위해서다.
그래서 “없으면 무시”가 맞는 상황에서 deleteById를 쓰면 예외 처리가 필요하고, 대량 삭제에서 SELECT가 부담이라면 @Modifying과 @Query로 DELETE 쿼리를 직접 쓰는 방법을 검토한다. 이 경우 영속성 컨텍스트와 콜백을 거치지 않는다는 점을 감안해야 한다.
- https://hwanchang.tistory.com/7
JPA Optional Return
Spring Data 리포지토리에서 단건 조회 메서드가 결과 없음을 표현하는 방법은 두 가지다. Spring Data JPA 문서에 따르면 단건을 반환하는 CRUD 메서드는 Optional로 값이 없을 수 있음을 나타낼 수 있고, 래퍼 타입을 쓰지 않으면 결과가 없을 때 null을 반환한다. 반면 컬렉션, 스트림 같은 반환 타입은 null을 반환하지 않고 빈 값을 반환한다고 보장한다.
1
2
3
Optional<Member> findByEmail(String email); // 없으면 Optional.empty()
Member findByNickname(String nickname); // 없으면 null
List<Member> findByAge(int age); // 없으면 빈 리스트
Optional로 반환하면 호출하는 쪽이 “없을 수 있음”을 타입으로 알게 되고, orElseThrow로 없을 때의 처리를 바로 이어 쓸 수 있다.
1
2
Member member = memberRepository.findByEmail(email)
.orElseThrow(() -> new MemberNotFoundException(email));
반대로 리스트를 반환하는 메서드를 Optional<List<...>>로 감쌀 필요는 없다. 결과가 없으면 이미 빈 리스트가 오기 때문이다.
- https://kkambi.tistory.com/193
댓글
아직 댓글이 없습니다