Framework & Library/Spring

[Java / Spring / JPA] Native Query와 QLRM 라이브러리

마볼링 2023. 1. 25. 08:18
JPA(Java persistence API)를 사용하여 서비스를 구현하다 보면 JPA에서 제공하는 기능만으로는 조회가 불가능한 경우가 존재한다.
대표적으로 엔티티 객체를 그대로 조회하는 것이 아닌 DTO에 맞춰서 조회하는 경우이다.

 

[ 예시 / 인스타그램 클론코딩 중 구독 정보 조회 커리 ]

SELECT u.id, u.username, u.profileImageUrl, 
if((SELECT 1 FROM subscribe 
WHERE fromUserId = 1 AND toUserId = u.id),1,0) subscribeState,
if((1=u.id),1,0) equalUserState
FROM user u INNER JOIN subscribe s
ON u.id = s.toUserId
WHERE s.fromUserId = 2;

이런식으로 필요한 데이터를 쿼리로 작성하고 스프링에 대입해주면 된다.

여러가지 방법이 존재하지만 손쉽게 할 수 있는 QLRM 라이브러리를 사용해보려고 한다.

 

[ build.gradle ]

implementation group: 'org.qlrm', name: 'qlrm', version: '3.0.4'

 

[ SubscribeSerive.java ]

@RequiredArgsConstructor
@Service
public class SubscribeService {

   private final SubscribeRepository subscribeRepository;
   private final EntityManager em; // Repository는 EntityManager를 구현해서 만들어져 있는 구현체

   @Transactional(readOnly = true)
   public List<SubscribeDto> 구독리스트(int principalId, int pageUserId) {
      // 쿼리 준비
      StringBuffer sb = new StringBuffer();
      sb.append("SELECT u.id, u.username, u.profileImageUrl, ");
      sb.append("if ((SELECT 1 FROM subscribe WHERE fromUserId = ? AND toUserId = u.id), 1, 0) subscribeState, "); // 물음표 principalId
      sb.append("if ((?=u.id), 1, 0) equalUserState "); // 물음표 principalId
      sb.append("FROM user u INNER JOIN subscribe s ");
      sb.append("ON u.id = s.toUserId ");
      sb.append("WHERE s.fromUserId = ?"); // 물음표 pageUserId

      // 쿼리 완성
      Query query = em.createNativeQuery(sb.toString())
         .setParameter(1, principalId)
         .setParameter(2, principalId)
         .setParameter(3, pageUserId);

      // 쿼리 실행 (qlrm 라이브러리 필요 = Dto에 DB결과를 매핑하기 위해서)
      JpaResultMapper result = new JpaResultMapper();
      List<SubscribeDto> subscribeDtos = result.list(query, SubscribeDto.class);
      return subscribeDtos;
   }
}
  • 해당 쿼리가 리턴하는 값이 Subscribe 타입이 아니기 때문에 사용하려는 Service에서 직접 Native Query를 작성해주어야한다.
    -> 그러기 위해 EntityManager를 DI 해준다.
  • 쿼리 준비를 위한 StringBuffer를 만들고 필요한 파라미터를 변수 바인딩 해준다.
    -> 변수를 ?로 바인딩하고, em.createNativeQuery를 이용하여 각각 변수를 바인딩 해줄 수 있다.
  • 해당 쿼리를 실행해주기 위해 JpaResultMapper를 사용해준다
    -> QLRM이 지원해주는 메소드이다.

 

해당 코드가 잘 작동하면 아래와 같이 데이터가 불러와진다.