스프링 데이터 JPA - 네이티브 쿼리
나머지 기능
거의 안쓰는 기능 (알고만 있자.)
가급적 네이티브 쿼리는 사용하지 않는게 좋음. 정말 어쩔 수 없을 때 사용 최근에 나온 궁극의 방법 → 스프링 데이터 Projections 사용
스프링 데이터 JPA 기반 네이티브 쿼리
- 페이징 지원
- 반환 타입
- Object[]
- Tuple
- DTO(스프링 데이터 인터페이스 Projections) 지원
- 제약
- Sort 파라미터를 통한 정렬이 정상 동작하지 않을 수 있음 (믿지 말고 직접 처리)
- JPQL처럼 애플리케이션 로딩 시점에 문법 확인 불가
- 동적 쿼리 불가
MemberRepository.java
1
2
@Query(value = "select * from member where username = ?", nativeQuery = true)
Member findByNativeQuery(String username);
다음과 같이 @Query(value = "select * from member where username = ?", nativeQuery = true)
이렇게 작성하면 실제 쿼리가 나가버린다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
@Test
public void nativeQueryTest() throws Exception {
//given
Team teamA = new Team("teamA");
em.persist(teamA);
Member m1 = new Member("m1", 0, teamA);
Member m2 = new Member("m2", 0, teamA);
em.persist(m1);
em.persist(m2);
em.flush();
em.clear();
//when
Member result = memberRepository.findByNativeQuery("m1");
//then
System.out.println("result = " + result);
}
다음과 같이 테스트 했고

진짜 쌩 SQL쿼리가 나간다.
그런데 제약이 너무 많다.
1
2
@Query(value = "select username from member where username = ?", nativeQuery = true)
Member findByNativeQuery(String username);
이렇게 username으로 바꿔버리면 Member로 리턴하기도 그렇고, 좀 애매하다.
네이티브 SQL을 DTO로 조회할 때는 JdbcTemplete or MyBatis 권장
- JPQL은 위치 기반 파라미터를 1부터 시작하지만 네이티브 SQL은 0부터 시작
- 네이티브 SQL을 엔티티가 아닌 DTO로 변환하려면
- DTO 대신 JPA TUPLE 조회
- DTO 대신 MAP 조회
- @SqlResultSetMapping → 복잡
- Hibernate ResultTransformer를 사용해야함 → 복잡
- 참고 링크
- 네이티브 SQL을 DTO로 조회할 때는 JdbcTemplete or MyBatis 권장
Projections 활용
예 ) 스프링 데이터 JPA 네이티브 쿼리 + 인터페이스 기반 Projections 활용
MemberProjection 인터페이스 생성
1
2
3
4
5
public interface MemberProjection {
Long getId();
String getUsername();
String getTeamName();
}
1
2
3
4
5
@Query(value = "select m.member_id as id, m.username, t.name as teamName" +
" from member m left join team t",
countQuery = "select count(*) from member",
nativeQuery = true)
Page<MemberProjection> findByNativeProjections(Pageable pageable);
다음과 같이 리포지토리 단에서 사용할 수 있다. 이번 케이스는 페이징을 하기 위한 메서드이며, 네이티브 쿼리를 사용했다. 또 페이징이기 때문에 countQuery도 작성해 주었다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
@Test
public void nativeQueryTest() throws Exception {
//given
Team teamA = new Team("teamA");
em.persist(teamA);
Member m1 = new Member("m1", 0, teamA);
Member m2 = new Member("m2", 0, teamA);
em.persist(m1);
em.persist(m2);
em.flush();
em.clear();
//when
Page<MemberProjection> result = memberRepository.findByNativeProjections(PageRequest.of(0, 10));
//then
List<MemberProjection> content = result.getContent();
for (MemberProjection memberProjection : content) {
System.out.println(memberProjection.getUsername());
System.out.println(memberProjection.getTeamName());
}
}
다음과 같이 페이징과 projection을 이용해서 native쿼리를 사용할 수 도 있다.

다음과 같이 우리가 작성한 쿼리 그대로 나가는 걸 볼 수 있다.
정적 쿼리를 Native쿼리로 사용할 때는 Projections 기능을 활용하는 편이 좋아 보인다. → 하지만 Native쿼리를 안 쓰는 방향, QueryDSL..
댓글남기기