posts - 495,  comments - 11,  trackbacks - 0

          4.5 SQL查詢

          Hibernate還支持使用SQL查詢,使用SQL查詢可以利用某些數據庫的特性,或者用于將原有的JDBC應用遷移到Hibernate應用上。使用命名的SQL查詢還可以將SQL語句放在配置文件中配置,從而提高程序的解耦,命名SQL查詢還可以用于調用存儲過程。

          如果是一個新的應用,通常不要使用SQL查詢。

          SQL查詢是通過SQLQuery接口來表示的,SQLQuery接口是Query接口的子接口,因此完全可以調用Query接口的方法:

          ?? ● setFirstResult(),設置返回結果集的起始點。

          ?? ● setMaxResults(),設置查詢獲取的最大記錄數。

          ?? ● list(),返回查詢到的結果集。

          但SQLQuery比Query多了兩個重載的方法:

          ?? ● addEntity,將查詢到的記錄與特定的實體關聯。

          ?? ● addScalar,將查詢的記錄關聯成標量值。

          執行SQL查詢的步驟如下:

          (1)獲取Hibernate Session對象;

          (2)編寫SQL語句;

          (3)以SQL語句作為參數,調用Session的createSQLQuery方法創建查詢對象;

          (4)如果SQL語句包含參數,調用Query的setXxx方法為參數賦值;

          (5)調用SQLQuery對象的addEntity或addScalar方法將選出的結果與實體或標量值關聯;

          (6)調用Query的list方法返回查詢的結果集。

          看下面的SQL查詢示例:

          private void test()

          {

          ??? //獲取Hibernate Session對象

          ??? Session session = HibernateUtil.currentSession();

          ??? //開始事務

          ??? Transaction tx = session.beginTransaction();

          ??? //編寫SQL語句

          ??? String sqlString = "select {s.*} from student s where s.name like '馬軍'";

          ??? //以SQL語句創建SQLQuery對象

          ??? List l = session.createSQLQuery(sqlString)

          ??????????????????? //將查詢到的記錄與特定實體關聯起來

          ??????????????????? .addEntity("s",Student.class)

          ??????????????????? //返回全部的記錄集

          ??????????????????? .list();

          ??? //遍歷結果集

          ??? Iterator it = l.iterator();

          ??? while (it.hasNext())

          ??? {

          ??????? //因為將查詢結果與Student類關聯,因此返回的是Student集合

          ??????? Student s = (Student)it.next();

          ??????? Set enrolments = s.getEnrolments();

          ??????? Iterator iter = enrolments.iterator();

          ??????? while(iter.hasNext())

          ??????? {

          ??????????? Enrolment e = (Enrolment)iter.next();

          ??????????? System.out.println(e.getCourse().getName());

          ??????? }

          ??? }

          ??? //提交事務

          ??? tx.commit();

          ??? //關閉Session

          ??? HibernateUtil.closeSession();

          }

          上面的示例顯示了將查詢記錄關聯成一個實體的示例。事實上,SQL查詢也支持將查詢結果轉換成標量值,轉換成標量值可以使用addScalar方法,如:

          Double max = (Double) session.createSQLQuery("select max(cat.weight) as maxWeight from cats cat")

          ??????? .addScalar("maxWeight", Hibernate.DOUBLE);

          ??????? .uniqueResult();

          使用SQL查詢,如果需要將查詢到的結果轉換成特定實體,就要求為選出的字段命名別名。這別名不是隨意命名的,而是以“/”實例名.屬性名“/”的格式命名,例如:

          //依次將多個選出的字段命名別名,命名別名時都以ss作為前綴,ss是關聯實體的別名

          String sqlStr = "select stu.studentId as {ss.studentNumber},"

          ??????? + "stu.name as {ss.name} from "

          ??????? + "student as stu where stu.name like '楊海華'";

          List l = session.createSQLQuery(sqlStr)

          ??????????? //將查詢出的ss實例,關聯到Student類

          ??????????? .addEntity("ss",Student.class)

          ??????????? .list();

          在第一個示例中,以{s.*}代表該表的全部字段,且關聯實例的別名也被指定為s。

          注意:如果不使用{s.*}的形式,就可讓實體別名和表別名互不相同。關聯實體的類型時,被關聯的類必須有對應的setter方法。

          4.5.1 命名SQL查詢

          可以將SQL語句不放在程序中,而放在配置文件中,這種方式以松耦合的方式配置SQL語句,可以提高程序解耦。

          在Hibernate的映射文件中定義查詢名,然后確定查詢所用的SQL語句,然后就可以直接調用該命名SQL查詢。在這種情況下,不需要調用addEntity()方法,因為在配置命名SQL查詢時,已經完成了查詢結果與實體的關聯。

          下面是命名SQL查詢的配置片段:

          <!-- 每個sql-query元素定義一個命名SQL查詢 -->

          <sql-query name="mySqlQuery">

          ??? <!-- 關聯返回的結果與實體類 -->

          ??? <return alias="s" class="Student"/>

          ??????? <!-- 定義命名SQL查詢的SQL語句 -->

          ???? ??? SELECT {s.*}

          ??????? from student s WHERE s.name like'楊海華'

          </sql-query>

          sql-query元素是hibernate-mapping元素的子元素。因此,sql-query定義的名可以直接通過Session訪問,上面定義的mySqlQuery查詢可以直接訪問,下面是使用該命名SQL查詢的示例代碼:

          private void testNamedSQl()

          {

          ??? //獲取Hibernate Session對象

          ??? Session session = HibernateUtil.currentSession();

          ??? //開始事務

          ??? Transaction tx = session.beginTransaction();

          ??? //調用命名查詢,直接返回結果

          ??? List l = session.getNamedQuery("mySqlQuery")

          ??????????????????? ???? .list();

          ??? //遍歷結果集

          ??? Iterator it = l.iterator();

          ??? while (it.hasNext())

          ??? {

          ??????? //在定義SQL查詢時,已經將結果集與Student類關聯起來

          ??????? //因此,集合里的每個元素都是Student實例

          ??????? Student s = (Student)it.next();

          ??????? Set enrolments = s.getEnrolments();

          ??????? Iterator iter = enrolments.iterator();

          ??????? while(iter.hasNext())

          ??????? {

          ??????????? Enrolment e = (Enrolment)iter.next();

          ??????????? System.out.println("=====================================");

          ??????????? System.out.println(e.getCourse().getName());

          ??????????? System.out.println("=====================================");

          ??????? }

          ??? }

          ??? tx.commit();

          ??? HibernateUtil.closeSession();

          }

          4.5.2 調用存儲過程

          Hibernate 3增加了存儲過程的支持,該存儲過程只能返回一個結果集。

          下面是Oracle 9i的存儲過程示例:

          CREATE OR REPLACE FUNCTION selectAllEmployments

          ??? RETURN SYS_REFCURSOR

          AS

          ??? st_cursor SYS_REFCURSOR;

          BEGIN

          ??? OPEN st_cursor FOR

          SELECT EMPLOYEE, EMPLOYER,

          STARTDATE, ENDDATE,

          REGIONCODE, EID, VALUE, CURRENCY

          FROM EMPLOYMENT;

          ????? RETURN st_cursor;

          END;

          如果需要使用該存儲過程,可以先將其定義成命名SQL查詢,例如:

          <!-- 定義命名SQL查詢,name屬性指定命名SQL查詢名 -->

          <sql-query name="selectAllEmployees_SP" callable="true">

          ??? <!-- 定義返回列與關聯實體類屬性之間的映射 -->

          ??? <return alias="emp" class="Employment">

          ??????? <!-- 依次定義每列與實體類屬性的對應 -->

          ??? ??? <return-property name="employee" column="EMPLOYEE"/>

          ??? ??? <return-property name="employer" column="EMPLOYER"/>

          ??? ??? <return-property name="startDate" column="STARTDATE"/>

          ??? ??? <return-property name="endDate" column="ENDDATE"/>

          ??? ??? <return-property name="regionCode" column="REGIONCODE"/>

          ??? ??? <return-property name="id" column="EID"/>

          ??????? <!-- 將兩列值映射到一個關聯類的組件屬性 -->

          ??? ??? <return-property name="salary">

          ??????????? <!-- 映射列與組件屬性之間的關聯 -->

          ??????? ??? <return-column name="VALUE"/>

          ??????? ??? <return-column name="CURRENCY"/>

          ??????? </return-property>

          ??? </return>

          ??? { ? = call selectAllEmployments() }

          </sql-query>

          調用存儲過程還有如下需要注意的地方:

          ?? ● 因為存儲過程本身完成了查詢的全部操作,所以調用存儲過程進行的查詢無法使用setFirstResult()/setMaxResults()進行分頁。

          ?? ● 存儲過程只能返回一個結果集,如果存儲過程返回多個結果集,Hibernate將僅處理第一個結果集,其他將被丟棄。

          ?? ● 如果在存儲過程里設定SET NOCOUNT ON,將有更好的性能表現。當然也可以沒有該設定。

          posted on 2009-07-19 09:02 jadmin 閱讀(1159) 評論(0)  編輯  收藏

          只有注冊用戶登錄后才能發表評論。


          網站導航:
           
          主站蜘蛛池模板: 安顺市| 祥云县| 会昌县| 陇西县| 仁布县| 仲巴县| 宁德市| 蓝田县| 金门县| 浮梁县| 湘潭县| 屏山县| 昌宁县| 肃南| 南和县| 柳河县| 北辰区| 新晃| 香格里拉县| 南汇区| 德安县| 木兰县| 麻阳| 韶山市| 东丰县| 石楼县| 开远市| 松阳县| 武功县| 镶黄旗| 扶沟县| 谢通门县| 莒南县| 达州市| 司法| 准格尔旗| 海林市| 闸北区| 象山县| 德兴市| 襄樊市|