상황

  1. Friend 테이블에 친구 요청 row를 추가하려고 한다.
  2. 요청 송신자와 수신자가 각각 Member 객체로 등록되어 있음. (Friend 엔티티에)
  3. 그럼 매 번 쿼리를 세 번씩 날려야 하나?
    1. 송신자 가져오기
    2. 수신자 가져오기
    3. 친구 요청 저장하기
public void addFriend(Long requesterId, Long addresseeId) {
    //여기서 한 번   
    Member requester = memberRepository.findById(requesterId)
                                       .orElseThrow(() -> new RuntimeException("Requester not found"));                   
    //여기서 두 번   
    Member addressee = memberRepository.findById(addresseeId)
                                       .orElseThrow(() -> new RuntimeException("Addressee not found"));
		//여기서 세 번
    Friend friend = new Friend();
    friend.setRequester(requester);
    friend.setAddressee(addressee);

    friendRepository.save(friend);
}

해결

  • JPA의 EntityManager에는 getReference()라는 함수가 존재.
  • find()를 사용하면 각 객체를 불러오기 위해 쿼리를 날려야 하지만 getReference()를 사용하면 각 객체 대신 임시 프록시 객체 생성
  • 고로 쿼리를 날리지 않고 Proxy객체만으로 데이터를 삽입할 수 있다!
public void addFriend(Long requesterId, Long addresseeId) {
		//쿼리를 날리지 않고 프록시 객체 생성
    Member requester = entityManager.getReference(Member.class, requesterId);
    Member addressee = entityManager.getReference(Member.class, addresseeId);
		//쿼리는 여기서 한 번만!
    Friend friend = new Friend();
    friend.setRequester(requester);
    friend.setAddressee(addressee);

    friendRepository.save(friend);
}

고려할 점

  • 해당하는 id에 맞는 객체가 존재하는지 검증이 이뤄지지 않음.
  • addressee에 대한 검증만 해 준다면 쿼리를 세 번에서 두 번으로 줄일 수 있다! (requester는 토큰 정보로 사용하기 때문에 괜찮을 것이라는 판단… 물론 중간에 탈퇴하는 경우도 생각해야 할 것 같긴 함.)

Leave a comment