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 | 결과 매핑 사용 |
728x90
'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 |