본문 바로가기
TIL

findById vs getReferenceById 차이(22.10.27 TIL)

by winteringg 2022. 10. 27.

 getById 는 왜 deprecated 되었을까? 라는 동기분의 질문에 대한 노아님의 견해인데, 추가로 답변 하단에 남겨주신 findBy~ 메서드와 getBy~ 메서드의 내부 구현에 차이점이 존재한다는 코멘트를 보고 궁금증이 생겨 찾아보았다.


 findById 와 getReferenceById 를 예시로 들어보자.

findById 는 CrudRepository 에 있는 메서드이고, getReferenceById 는 JPARepository 에 있는 메서드이다.

//CrudRepository
public interface CrudRepository<T,ID> {
    ...
    Optional<T> findById(ID id);
    Iterable<T> findAll();
    ...
}


//JpaRepository
public interface JpaRepository<T,ID> {
    ...
    T getOne(ID id);
    List<T> findAll();
    ...
}


 두 메서드가 하는 일은 식별자인 id 를 통해 entity 를 알 수 있는 것으로 동일한데, 작지만 중요한 차이점이 하나 있는데 바로 메서드 명명이다. CrudRepository 의 find 는 리턴값이 없을 수 있지만, get 은 리턴값이 무조건 있어야 한다. 만약 getBy~ 를 호출했을 때 리턴값이 없으면 예외를 일으킨다. 이름 자체도 find 는 찾는 것이고, get 은 가져오는 것이다. 

 메서드 설명란을 보면, findById 는 엔티티가 있을 경우 반환하고, 만약 없을 경우 empty() 를 반환한다. 빈 목록에 대한 예외처리가 따로 없기 때문에 이 메서드를 호출할 때 엔티티가 없는 경우도 생각해서 개발자가 어떠한 처리를 해주어야 한다. (ID 가 null 일 경우는 IllegalArgumentException 예외를 던진다.)

 반면 getReferenceById 는 엔티티(에 대한 참조) 를 반환하고, 없는 경우 EntityNotFoundException 예외를 던진다. 이 경우 엔티티가 존재하지 않으면 invalid 상태이다. 하지만 알아서 예외를 던져주기 때문에 이 메서드를 호출할 시 따로 어떤 처리를 해주지 않아도 된다.

findById
getReferenceById

  간단한 사용 예시를 살펴보자. 예를 들어, 서점을 구현했다고 가정하면, 이 서점에서 사용자는 제목으로 책을 검색하게 된다. 이 경우 결과값은 없을 수도 있다. 사용자가 오타를 내서 검색을 했거나, 실제 해당 책이 이 서점에 존재하지 않을 수 있기 때문이다. 이 때 findById 를 사용한다.

 만약 사용자가 원하는 책을 찾아서 주문까지 완료했다고 가정해보자. 서점은 해당 주문에 대한 결제를 처리하기 위해 사용자에게 인보이스를 보내야 한다. 이 경우, 주문을 로드하고 사용자가 구매한 책을 조회하여 해당 책의 가격을 알아야 한다. 책을 주문한 히스토리가 무조건 있어야 하는 것이다. 이 때 getReferenceById 를 사용한다.

 추가로 단순히 Optional.empty() 를 반환하는지, 혹은 내부에서 예외를 발생시키는지의 차이 말고도 다른 점이 있다. 바로 lazy loading (지연 로딩) 이다.

getReferenceById 메서드로 반환된 객체는 내부의 정보를 요청하는 시점에 DB 를 조회한다. 조금 더 자세히 말하자면, getReferenceById 는 EntityManager 의 getReference 메서드를 호출하여 참조값만 가져온 후, 조회된 entity 의 내부 값이 필요해지는 시점에 lazy loading 으로 DB 를 조회해 값을 가져온다. 즉, 내부의 값을 필요로 하지 않고, 다른 객체에게 할당하는 목적으로만 조회하는 경우 getReferenceById 가 성능상 이점이 있을 수 있다는 것이다. 

 이런 의미에서 deprecated 된 getById 보다는 getReferenceById 가 참조값만 가져오는 메서드라는 점에서 훨씬 더 정확한 의미로 전달되는 것 같다.

 

 

 

참고 :

 

find vs. get – Thomas Uhrig

Three years ago I wrote a blog post with the provoking title “Don’t use Optionals for data repositories“. The post received a couple of critical comments and I had the feeling that I didn’t made my point clear. This week I stumbled over the same to

tuhrig.de

 

 

getById vs findById

getById 내부적으로 EntityManager.getReference() 메소드를 호출하기 때문에 엔티티를 직접 반환하는 것이 아니라 프록시만 반환합니다. 프록시만 반환하기 때문에 실제로 사용하기 전까지는 DB에 접근하

white-gyu.github.io

댓글