首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 綜合教學

Hibernate 原生 SQL 查詢完全指南:標量、實體、關聯與存儲過程

     編輯:Java 綜合教學

Hibernate 原生 SQL 查詢完全指南:標量、實體、關聯與存儲過程

當 HQL 或 Criteria 無法滿足複雜查詢需求(如多表連接、特定數據庫函數、優化慢查詢)時,Hibernate 提供的原生 SQL 查詢成為強有力的補充。本文系統總結 SQLQuery 接口的核心用法,覆蓋標量查詢、實體查詢、關聯處理、命名查詢及存儲過程調用。

一、原生 SQL 查詢基礎流程

  1. 獲取 Session 對象
  2. 編寫原生 SQL 語句
  3. 調用 session.createSQLQuery(sql) 獲取 SQLQuery 對象
  4. 根據需求調用 addScalar()(標量)或 addEntity()(實體)映射結果
  5. 若有參數,調用 setParameter() 綁定值
  6. 調用 list() 或 uniqueResult() 執行查詢

二、標量查詢:輕量級數據提取

返回 Object[] 列表,每個元素對應一行數據的字段值。默認使用 ResultSetMetaData 推斷類型,性能稍弱。推薦显式指定字段與類型:

List list = session.createSQLQuery("SELECT * FROM person_info")
    .addScalar("person_id", StandardBasicTypes.INTEGER)
    .addScalar("name", StandardBasicTypes.STRING)
    .addScalar("age", StandardBasicTypes.INTEGER)
    .list();

for (Object[] row : list) {
    System.out.println("ID: " + row[0] + ", Name: " + row[1] + ", Age: " + row[2]);
}

addScalar 雙重作用:① 限定返回列(未聲明的列不會出現在結果中)② 显式指定類型,避免 MetaData 開銷。

三、實體查詢:直接映射持久化對象

前提:SQL 必須查出映射實體的所有字段(含關聯外鍵)。

// 單表實體查詢
List<Person> persons = session.createSQLQuery("SELECT * FROM person_info")
    .addEntity(Person.class)
    .list();

// 多表連接查詢多個實體(需別名)
String sql = "SELECT p.*, e.* FROM person_inf p INNER JOIN event_inf e ON p.person_id = e.person_id";
List list = session.createSQLQuery(sql)
    .addEntity("p", Person.class)
    .addEntity("e", Event.class)
    .list();

for (Object[] row : list) {
    Person p = (Person) row[0];
    Event e = (Event) row[1];
    System.out.println(p.getName() + " - " + e.getTitle());
}

四、關聯與繼承處理:addJoin 預加載

解決 N+1 問題,通過 addJoin() 將關聯集合一併查詢並初始化:

String sql = "SELECT p.*, e.* FROM person_inf p, event_inf e WHERE e.person_id = p.person_id";
List list = session.createSQLQuery(sql)
    .addEntity("p", Person.class)
    .addJoin("e", "p.myEvents") // 關聯路徑:Person.myEvents
    .list();
// 返回的 Person 對象,myEvents 集合已完全初始化,無需額外查詢

五、命名查詢:SQL 與代碼解耦

在映射文件(.hbm.xml)或註解中定義:

<sql-query name="personEventQuery">
    <return alias="p" class="Person"/>
    <return alias="e" class="Event"/>
    <return-scalar column="p.age" type="int"/>
    SELECT p.*, e.* FROM person_inf p, event_inf e 
    WHERE p.person_id = e.person_id AND p.age = :age
</sql-query>

代碼中直接調用:

List list = session.getNamedQuery("personEventQuery")
    .setInteger("age", 30)
    .list();

可通過 <resultset> 復用結果映射配置。

六、調用存儲過程

要求:函數必須返回結果集;存儲過程第一個參數為 OUT 類型的結果集游標。

<sql-query name="callSelectPerson" callable="true">
    <return class="Person">
        <return-property name="name" column="name"/>
        <return-property name="age" column="age"/>
        <return-property name="id" column="person_id"/>
    </return>
    {CALL select_person()}  -- 或 EXEC select_person
</sql-query>

Java 調用同普通命名查詢:session.getNamedQuery("callSelectPerson").list()。

七、最佳實踐建議

  • 優先使用 HQL/JPQL,原生 SQL 作為補充
  • 嚴格使用 addScalar/addEntity 避免 MetaData 開銷
  • 多表查詢務必使用別名,防止列名衝突
  • 命名查詢集中管理 SQL,便於 DBA 優化維護
  • 存儲過程調用注意跨數據庫兼容性(語法差異大)
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved