'hql'에 해당되는 글 1건

  1. 2013.06.25 하이버네이트 프로그래밍 - 9장 HQL 살펴보기

** 본 요약은 한빛미디어 '하이버네이트 프로그래밍' 책을 기준으로 작성되어져 있다.

** 본 설명은 바로 따라하기 하기엔 어려움이 있다. 책을 보지 않은 사람에게는 간단히 어떤 기능을 제공하는지 이해하는데 목적을 둔다.

** 하이버네이트 3.2.5.ga 버전, Ant 빌드를 기본적으로 사용한다.


9장 HQL 살펴보기

본 장에서는 HQL 사용법, 그리고 HQL과 SQL의 차이점에 대해 설명합니다. 주요 내용은 다음과 같습니다. 


- HQL 사용방법

-> 테이블의 모든 데이터 조회하기

-> 프로퍼티와 일부분 선택하기

-> HQL을 이용해 정렬 하기

-> HQL을 이용해 통계 정보 가져오기

- 네이티브 SQL 이용하기

  


HQL 사용방법


HQL을 사용할 때 반드시 데이터를 다룰 클래스를 지정합니다. Track 인스턴스의 리스트를 가져오는 최소한의 쿼리의 예시는 다음과 같습니다.


from Track

또는 

from com.oreilly.hh.data.Track


위와 같이 하이버네이트는 매핑한 클래스의 이름을 자동으로 임포트 합니다. 하지만 하나 이상의 클래스에서 동일한 이름을 사용한다면 패키지명까지 기입해서 사용합니다. 주위할 점은 위 Track은 테이블명을 지칭하는 것이 아닌 클래스이다. 


만약 동일한 이름을 가진 하나 이상의 매핑 클래스가 있습니다면 다음 방법을 이용합니다. 

  - 인스터스 이름 명시할때 전체 패키지명을 기입한다.

  - 매핑 문서에 import 태그를 사용해 한 쪽 또는 양 쪽 클래스를 대체하는 이름을 선언해야 한다.

  - 매핑 문서의 hibernate-mapping 태그 속성에 auto-impot="false"를 추가해 자동 import 기능을 중지시킨다.

  


HQL의 특징 


from 절에 인스턴스명을 넣는 방법과 유사하게, 자바의 다형성을 HQL에서 이용할 수 있습니다. 만약 다음과 같이 HQL을 작성하면 데이터베이스의 모든 객체를 가져올 수 있습니다. 


from java.lang.Object


Object는 모든 자바 객체의 부모이기 때문에, 이를 기본적으로 상속받는 모든 객체가 검색 대상이 됩니다. 인스턴스를 확장한 클래스의 부모 클래스 혹은 인터페이스로 지정하면 해당 객체를 상속/구현한 객체가 검색 대상이 됩니다. 이러한 기능은 포괄적으로 데이터를 다룰때 유용합니다. 하지만 제약이 있는데, 전체 결과에 대해 order by  절을 사용할 수 없고, 결과에 대해 Query이너페이스의 scroll() 메소드를 사용할 수 없습니다. 

 


프로퍼티 일부분만 선택해 사용하기 


기존의 HQL은 Select 절이 없고, From절만 사용해 객체 전체를 반환하는 방법만 사용했습니다. 그런데 리포트를 만들때 사용하게 된다면 특정 값만 필요할 때도 있습니다. HQL에서는 SQL의 Select 절과 같은 방법으로 프로퍼티 일부분만 가져 올 수 있습니다.  


만약 playtime이 지정한 조건보다 작은 Track의 제목만 가져오고 싶을 때 다음과 같이 작성할 수 있습니다.


select track.title

from com.oreilly.hh.track as track

where track.playTime <= :length


그리고 코드에서는 해당 쿼리가 반환하는 값은 String의 List를 반환합니다. 여기서 하나 이상의 속성 값을 가져오고 싶을 때는 어떻게 해야 할까요? 이것 또한 기존의 SQL처럼 속성값을 넣어서 작성할 수 있습니다.


select track.id, track.title 

from com.oreilly.hh.track as track

where track.playTime <= :length


위와 같이 쉼표(,)로 구분해서 프로퍼티를 나열하는 것입니다. 위 쿼리가 반환하는 값은 각 결과 값은 Object 배열을 포함하는 값입니다. 다음 코드를 보면서 어떻게 접근하는지 확인합니다. 


List titles = tracksNoLongerThan(Time.valueOf("00:05:00"), session);

for (ListIterator iter = titles.listIterator(); iter.hasNext;) {

  Object[] row = (Object[])iter.next();

  Integer id = (Integer)row[0];

  String title = (String)row[1];

  System.out.println("Track: " + title + " [ID=" + id + "]");

}


이러한 기능을 사용하는 이유는 여러 값을 다른 매핑 클래스에서 골라 가져올때 유용하게 사용할 수 있습니다. 이때 모든 객체를 가져오는 방식보다 성능에 대한 이점을 기대할 수 있다. 


반환하는 값을 특정 객체를 지정할 수 있습니다.. 만약 TrackSummary 클래스의 생성자가 id와 title 프로퍼티를 받도록 한다면 다음과 같이 쓸 수 있습니다. 


select new TrackSummary(track.id, track.title)



정렬 방법


HQL을 작성하는 법을 보면, 기존 SQL과 비슷한 문법을 확인할 수 있습니다. 정렬도 SQL과 비슷한 방법으로 order by 절을 추가해 정렬 기능을 추가할 수 있다. 다음은 샘플 코드입니다.


select track.id, track.title 

from com.oreilly.hh.track as track

where track.playTime <= :length

order by track.title desc



통계 함수 값 다루기 


리포트 관련 정보를 다루다 보면, 데이터의 개수, 평균 등의 통계값이 필요할 때가 있다. HQL에도 SQL처럼 집합 함수 기능이 있습니다. count(), min(), max() 와 같이 동일한 함수명을 이용해 집합 함수 기능을 사용할 수 있습니다.


select count(*), min(track.playTime), max(track.playTime)

from Track as track


위 결과 값은 하나의 결과만 나타나기 때문여 Query인터페이스의 uniqueResult()라는 메소드를 이용하 한 개의 열만 반환하는 메소드를 사용할 수 있습니다. 결과 값은 일부분 속성값을 가져오는 것과 같이 Object배열이 됩니다.




네이티브 SQL 쿼리를 이용하기


특정 SQL Dialect만 지원하는 HQL을 작성한다면, 데이터베이스 변경을 매우 어렵게합니다. 또는 기존 JDBC 기반의 프로젝트를 하이버네이트로 이관할 때 최소한의 작업만 하고 싶을 경우, 기존의 SQL을 재활용하고 싶을때 기존 SQL을 하이버네이트에서 사용할 수 있는 방법을 제공합니다. 


네이티브 SQL 쿼리를 사용하기 위해서는 다음 방법을 사용합니다. 

  1) 매핑 클래스내에 query 태그 대신 sql-query 태그를 사용합니다.

  2) sql-query 태그 내에 반환하려는 매핑 클래스와 클래스를 쿼리 내에서 참조 할 수 있는 별칭을 지정해야 합니다. 쿼리 내에 별칭(alias)는 모두 중괄호({})로 감싸야만 합니다. 

  

다음은 네이티브 SQL을 작성한 예입니다. 


<sql-query name="com.oreilly.hh.tracksEndingAt">

  <return alias="track" class="com.oreilly.hh.data.Track"/>

  <![CDATA[

       select {track.*}

      from TRACK as {track}

      where SECOND({track}.PLAYTIME) = :seconds

    ]]>

</sql-query>

  

네임드 파라미터의 경우 기존의 HQL에서 처럼 중괄호를 사용하지 않고 똑같이 사용할 수 있습니다.


Posted by 빌리 :