Spring/SpringDataJPA

네이티브 쿼리

느리지만 꾸준하게 2022. 4. 19. 17:50

JPA가 SQL query를 그대로 사용하는 네이티브 쿼리를 지원한다.

하지만

  • 가급적 네이티브 쿼리는 사용하지 않는게 좋다.
  • 최근에 나온 final 방법 => 스프링 데이터 Projections 활용 

 

스프링 데이터 JPA 기반 네이티브 쿼리

  • 페이징 지원
  • 반환 타입
  • Object[]
  • Tuple
  • DTO(스프링 데이터 인터페이스 Projections 지원)

제약이 있는데

  • Sort 파라미터를 통한 정렬이 정상 동작하지 않을 수 있고
  • JPQL처럼 Application loading 시점에 문법 확인이 불가하고
  • 동적 쿼리가 불가능하다.

 

// MemberRepository Interface


@Query(value = "select * from member where username = ?", nativeQuery = true)
Member findByNativeQuery(String username);

 

test를 돌려보면 sql이 select절 그대로 나가게 된다.

// MemberRepository

@Query(value = "select * from member where username = ?", nativeQuery = true)
Member findByNativeQuery(String username);
// MemberRepositoryTest

@Test
public void nativeQuery() {
    // 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");
    System.out.println("result = " + result);
}
select * from member where username = ?
select * from member where username = 'm1';
result = Member(id=2, username=m1, age=0)

 

 

아래와 같은 설정을 한번 해보자.

// MemberProjection Interface

package study.datajpa.repository;

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);

 

test를 돌리게 되면 

// MemberRepositoryTest

@Test
    public void nativeQuery() {
        // 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를 0을 설정을 해주고
        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 ?
        
        
        
        
memberProjection = m1
memberProjection = teamA
memberProjection = m2
memberProjection = teamA

 

 

 

이렇게 네이티브 쿼리에서 매칭을 해주면 

// MembeRepository

@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);

 

projection 기능을 그대로 써서 네이티브 쿼리에 대한 문제를 심플하게 해결할 수가 있다.

// MemberProjection Interface

package study.datajpa.repository;

public interface MemberProjection {

    Long getId();
    String getUsername();
    String getTeamName();
}

그래도 이거대신에 스프링의 JDBC Template이나 Mybatis를 쓰자!

 

끝으로 QueryDSL강의까지 계속 달려보자!

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

<출처 김영한: 실전! 스프링 데이터 JPA >

https://www.inflearn.com/course/%EC%8A%A4%ED%94%84%EB%A7%81-%EB%8D%B0%EC%9D%B4%ED%84%B0-JPA-%EC%8B%A4%EC%A0%84/dashboard

 

실전! 스프링 데이터 JPA - 인프런 | 강의

스프링 데이터 JPA는 기존의 한계를 넘어 마치 마법처럼 리포지토리에 구현 클래스 없이 인터페이스만으로 개발을 완료할 수 있습니다. 그리고 반복 개발해온 기본 CRUD 기능도 모두 제공합니다.

www.inflearn.com

 

'Spring > SpringDataJPA' 카테고리의 다른 글

Projections  (0) 2022.04.19
Query By Example  (0) 2022.04.19
Specifications(명세)  (0) 2022.04.19
새로운 엔티티를 구별하는 방법  (0) 2022.04.18
스프링 데이터 JPA 구현체 분석  (0) 2022.04.18