JVM/JPA

네이티브 SQL

kyoulho 2023. 6. 30. 13:31

JPQL을 사용할 수 없을 때 SQL을 직접 사용할 수 있는 기능을 네이티브 SQL이라 한다. 네이티브 SQL을 사용하면 엔티티를 조회할 수 있고 JPA가 지원하는 영속성 컨텍스트의 기능을 그대로 사용할 수 있다.

 

엔티티 조회

실제 데이터베이스 SQL을 사용한다는 것과 위치기반 파라미터만 지원한다는 차이가 있다.

하이버네이트는 이름 기반 파라미터를 지원한다.

String sql = "SELECT ID, AGE, NAME, TEAM_ID FROM MEMBER WHERE AGE > ?";
Query nativeQuery = em.createNativeQuery(sql, Member.class).setParameter(1, 20);
List<Member> resultList = nativeQuery.getResultList();

 

값 조회

타입 정보를 넘기지 않으면 Object[]에 담아서 반환한다. 결과는 영속성 컨텍스트가 관리하지 않는다.

String sql = "SELECT ID, AGE, NAME, TEAM_ID FROM MEMBER WHERE AGE > ?";
Query nativeQuery = em.createNativeQuery(sql).setParameter(1, 10);
List<Object[]> resultList = nativeQuery.getResultList();

 

결과 매핑 

엔티티와 값을 함께 조회할 때 사용한다.

// 결과 매핑 사용
String sql = "SELECT M.ID, AGE, NAME, TEAM_ID, I.ORDER_COUNT " +
                "FROM MEMBER M " +
                "LEFT JOIN " +
                "(SELECT IM.Id, COUNT(*) AS ORDER_COUNT " +
                "FROM ORDERS O, MEMBER IM " +
                "WHERE O>MEMBER_ID = IM.ID) I " +
                "ON M.ID = I.ID";
 Query nativeQuery = em.createNativeQuery(sql, "memberWithOrderCount");
 for (Object[] objects : resultList) {
     Member member = (Member) objects[0];
     BigInteger orderCount = (BigInteger) objects[1];
 }
 
 // 결과 매핑 정의
 @SqlResultSetMapping(name = "memberWithOrderCount",
        entities = {@EntityResult(entityClass = Member.class)},
        columns = {@ColumnResult(name = "ORDER_COUNT")})
public class Member {...}
// 결과 매핑 사용
 em.createNativeQuery(
                "SELECT o.id AS order_id, " +
                        "o.quantity AS order_quantity," +
                        " o.iterm AS order_item," +
                        " i.name AS item_name " +
                        "FROM Order o, Item i " +
                        "WHERE (order_quantity > 25) AND " +
                        "(order_item = i.id)", "OrderResults");
// 결과 매핑 정의                        
@SqlResultSetMapping(name = "OrderResults",
        entities = {
                @EntityResult(entityClass = Order.class,
                        fields = {
                                @FieldResult(name = "id", column = "order_id"),
                                @FieldResult(name = "quantity", column = "order_quantity"),
                                @FieldResult(name = "item", column = "order_item")})},
        columns = {
                @ColumnResult(name = "item_name")}
)

@SqlResultSetMapping

속성 기능
name 결과 매핑 이름
entities @EntityResult를 사용해서 엔티티를 결과로 매핑한다.
columns @ColumnResult를 사용해서 컬럼을 결과로 매핑한다.

@EntityResult

속성 기능
entityClass 결과로 사용할 엔티티 클래스를 지정한다.
fields @FieldResult를 사용해서 결과 컬럼을 필드와 매핑한다.
discriminatorColumn 엔티티의 인스턴스 타입을 구분하는 필드(상속에서 사용)

@FieldResult

속성 기능
name 결과를 받을 필드명
column 결과 컬럼명

@ColumnResult

속성 기능
name 결과 컬럼명

 

Named 네이티브 SQL

Spring JPA를 쓰면 쓸일이 없을거 같다.

// 정의
@Entity
@SqlResultSetMapping(name = "memberWithOrderCount",
        entities = {@EntityResult(entityClass = Member.class)},
        columns = {@ColumnResult(name = "ORDER_COUNT")})
@NamedNativeQuery(
    name = "Member.memberWithOrderCount",
    query= "...",
    resultSetMapping = "memberWithOrderCount"
)
public class Member {...}

// 사용
List<Object[]> resultList = em.createNamedQuery("Member.memberWithOrderCount")
			.getResultList();
속성 기능
name 네임드 쿼리 이름(필수)
query SQL 쿼리(필수)
hints 벤더 종속적인 힌트
resultClass 결과 클래스
resultSetMapping 결과 매핑 사용

 

'JVM > JPA' 카테고리의 다른 글

객체지향 쿼리 심화  (0) 2023.06.30
스토어드 프로시저(JPA 2.1)  (0) 2023.06.30
QueryDSL  (0) 2023.06.28
JPQL 다형성 쿼리, 사용자 정의 함수, Named 쿼리  (0) 2023.06.28
JPQL 조건식  (0) 2023.06.28