반응형
Spring Data JPA 게시글은 대부분 인프런의 김영한님의 강의인 '실전! 스프링 데이터 JPA' 기반으로 내용을 정리했습니다.
네이티브 쿼리
네이티브 쿼리는 JPA에서 제공하는 기능이며 일반적으로 우리가 사용하는 SQL을 사용할 수 있도록 해주는 기능이다. 가급적 네이티브 쿼리는 사용하지 않는 것이 좋다. 정말 최후의 수단으로.. 어쩔 수 없는 상황에만 사용하는 걸 권장한다.
스프링 데이터 JPA 기반 네이티브 쿼리
- MemberRepository.interface
@Query(value = "select * from member where username = ?", nativeQuery = true)
Member findByNativeQuery(String username);
- MemberRepositoryTest.class
@Test
public void nativeQuery() {
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();
Member result = memberRepository.findByNativeQuery("m1");
System.out.println("result = " + result);
}
select
*
from
member
where
username = ?
result = Member(id=2, username=m1, age=0)
이렇게 사용하면 되는 기능이다. 근데 이 기능은 제약이 되게 많다. 일단 엔티티의 한 컬럼의 데이터만 가져오려면 반환 타입을 변경해야 하는데 반환 타입으로 지정할 수 있는 게 너무 한정적이다. 그리고 뭔가 네이티브 쿼리를 사용해서 데이터를 가져오는 행위 자체가 단순한 조회 목적이라기 보다는 엄청 대용량의 데이터를 join 하거나 할 때 쓰는 등의 제약이 있다.
정리하자면
- 반환 타입
- Object[]
- Tuple
- DTO(원래는 안됐었지만 최근에 업데이트 됨)
- 제약
- Sort 파라미터를 통한 정렬이 정상적으로 동작하지 않을 수 있다.(직접 처리해야 함. 어쩔땐 되고, 어쩔땐 안 된다.)
- JPQL처럼 애플리케이션 로딩 시점에 문법 확인이 불가능하다.
- 동적 쿼리가 불가능하다.
- 네이티브 SQL을 DTO로 조회할 때는 JdbcTemplate이나 myBatis를 사용하는 걸 권장한다.
Projections 활용
그래도 Projections를 활용하면 더 쉽게 사용할 수 있다. 단 동적 쿼리는 사용하기 쉽지 않다.
- MemberProjection.interface
public interface MemberProjection {
Long getId();
String getUsername();
String getTeamName();
}
- MemberRepository.interface
@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>findByNativeProjection(Pageable pageable);
JPA가 아니라서 count 쿼리를 직접 만들어줘야 한다.
- MemberRepositoryTest.class
Page<MemberProjection> result = memberRepository
.findByNativeProjection(PageRequest.of(0, 10));
List<MemberProjection> content = result.getContent();
for (MemberProjection memberProjection : content) {
System.out.println("memberProjection = " + memberProjection.getUsername());
System.out.println("memberProjection = " + memberProjection.getTeamName());
}
select
m.member_id as id,
m.username,
t.name as teamName
from
Member m
left join
team t limit ? offset ?
select
count(*)
from
member
memberProjection = m1
memberProjection = teamA
memberProjection = m2
memberProjection = teamA
반응형