一、概述
HQL(Hibernate Query Language) 是面向對象的查詢語言,它和 SQL 查詢語言有些相似,在 Hibernate 提供的各種檢索方式中,HQL 是使用最廣的一種檢索方式。它有如下功能:
- 在查詢語句中設定各種查詢條件
- 支持投影查詢, 即僅檢索出對象的部分屬性
- 支持分頁查詢
- 支持連接查詢
- 支持分組查詢,允許使用
HAVING
和GROUP BY
關鍵字 - 提供內置聚集函數,如
sum()
、min()
和max()
- 支持子查詢
- 支持動態綁定參數
- 能夠調用用戶定義的 SQL 函數或標準的 SQL 函數
提供了以下幾種檢索對象的方式
- 導航對象圖檢索方式:根據已經加載的對象導航到其他對象
- OID 檢索方式:按照對象的 OID 來檢索對象
- HQL 檢索方式:使用面向對象的 HQL 查詢語言
- QBC 檢索方式:使用 QBC(Query By Criteria) API 來檢索對象。這種 API 封裝了基於字符串形式的查詢語句,提供了更加面向對象的查詢接口
- 本地 SQL 檢索方式:使用本地數據庫的 SQL 查詢語句
二、HQL檢索方式
1、步驟
① 創建Query對象:通過 Session
的 createQuery()
方法創建一個 Query 對象,它包括一個 HQL 查詢語句。HQL 查詢語句中可以包含命名參數
② 動態綁定參數
③ 調用 Query 相關方法執行查詢語句
@Test
public void test(){
//1.創建Query對象
String hql = "from Employee e where e.salary > :sal and e.email like :email";
Query query = session.createQuery(hql);
//2.綁定參數
query.setFloat("sal",1500).setString("email","%qq%");
//3.執行查詢
List<Employee> list = query.list();
System.out.println(list.size());
}
- Query接口支持方法鏈編程風格, 它的
setXxx()
方法返回自身實例,而不是void
類型 - HQL vs SQL:
① HQL 查詢語句是面向對象的,Hibernate 負責解析 HQL 查詢語句,然後根據對象-關係映射文件中的映射信息,把 HQL 查詢語句翻譯成相應的 SQL 語句。HQL 查詢語句中的主體是域模型中的類及類的屬性
② SQL 查詢語句是與關係數據庫綁定在一起的,SQL 查詢語句中的主體是數據庫表及表的字段
2、綁定參數
Hibernate的參數綁定有兩種形式:
① 按參數名字綁定:在 HQL 查詢語句中定義命名參數,命名參數以 “:”
開頭
String hql = "from Employee e where e.salary > :sal and e.email like :email";
Query query = session.createQuery(hql);
query.setFloat("sal",1500).setString("email","%qq%");
② 按參數位置綁定:
String hql = "from Employee e where e.salary > ? and e.email like ?";
Query query = session.createQuery(hql);
query.setFloat(0,1500).setString(1,"%qq%");
- 參數還可以是實體類類型
- HQL採用
ORDER BY
關鍵字對查詢結果排序
3、分頁查詢
setFirstResult(int firstResult)
:設定從哪一個對象開始檢索,參數 firstResult 表示這個對象在查詢結果中的索引位置,索引位置的起始值爲 0。默認情況下,Query 從查詢結果中的第一個對象開始檢索setMaxResults(int maxResults)
:設定一次最多檢索出的對象的數目。在默認情況下,Query
和Criteria
接口檢索出查詢結果中所有的對象
@Test //分頁查詢
public void testPageQuery(){
String hql = "from Employee";
Query query = session.createQuery(hql);
int pageNo = 1; //起始頁
int pageSize = 4; //每頁最多顯示的數據數
List<Employee> emps = query
.setFirstResult((pageNo-1)*pageSize)
.setMaxResults(pageSize)
.list();
System.out.println(emps);
}
4、命名查詢
- Hibernate 允許在映射文件中定義字符串形式的查詢語句.
<query>
元素用於定義一個 HQL 查詢語句,它和<class>
元素並列。- 在程序中通過
Session
的getNamedQuery()
方法獲取查詢語句對應的 Query 對象
5、投影查詢
- 投影查詢:查詢結果僅包含實體的部分屬性,通過
SELECT
關鍵字實現 Query
的list()
方法返回的集合中包含的是數組類型的元素,每個對象數組代表查詢結果的一條記錄- 可以在持久化類中定義一個對象的構造器來包裝投影查詢返回的記錄,使程序代碼能完全運用面向對象的語義來訪問查詢結果集
- 可以通過
DISTINCT
關鍵字來保證查詢結果不會返回重複元素
根據以上實例總結得出:
① 通過testFieldQuery()中的方式,返回的是一個對象數組的集合
② 通過testFieldQuery2()中的返回,返回的是一個實體類對象的集合。前替條件是:在實體類對象中要有相對應的有參構造函數和無參構造函數6、報表查詢
- 報表查詢用於對數據分組和統計,與 SQL 一樣,HQL 利用
GROUP BY
關鍵字對數據分組
,用HAVING
關鍵字對分組數據設定約束條件
。 - 在 HQL 查詢語句中可以調用以下聚集函數
count() --查詢總數
min() --最小值
max() --最大值
sum() --求和
avg() --平均值
實例代碼如下:
@Test
public void testGroupBy(){
String hql = "select min(e.salary),max(e.salary) from Employee e " +
"group by e.dept having min(salary) > :minSal";
Query query = session.createQuery(hql);
query.setFloat("minSal",1000);
List<Object[]> list = query.list();
for (Object[] objs:list){
System.out.println(Arrays.asList(objs));
}
}
7、HQL (迫切)左外連接
【1】迫切左外連接
LEFT JOIN FETCH
關鍵字表示迫切左外連接檢索策略list()
方法返回的集合中存放實體對象的引用,每個 Department 對象關聯的 Employee 集合都被初始化,存放所有關聯的 Employee 的實體對象- 查詢結果中可能會包含重複元素,可以通過一個
HashSet
來過濾重複元素
@Test
public void testLeftJoinFetch(){
// String hql = "from Department d LEFT JOIN FETCH d.emps";
//方法1:直接在HQL語句中去重
String hql = "SELECT DISTINCT d FROM Department d LEFT JOIN FETCH d.emps";
Query query = session.createQuery(hql);
List<Department> depts = query.list();
//方法2:使用xxxSet()去重
// depts = new ArrayList<>(new LinkedHashSet<>(depts));
System.out.println(depts.size());
for (Department dept:depts){
System.out.println(dept.getDeptName()+dept.getEmps().size());
}
}
【2】 左外連接
LEFT JOIN
關鍵字表示左外連接查詢.list()
方法返回的集合中存放的是對象數組類型- 根據配置文件來決定 Employee 集合的檢索策略
- 如果希望
list()
方法返回的集合中僅包含 Department 對象,可以在HQL 查詢語句中使用 SELECT 關鍵字
實例代碼:
@Test
public void testLeftJoin(){
String hql = "select distinct d from Department d LEFT JOIN d.emps";
Query query = session.createQuery(hql);
//返回的是一個數組的集合
// List<Object[]> list = query.list();
// System.out.println(list);
//
// for (Object[] objs:list){
// System.out.println(Arrays.asList(objs));
// }
List<Department> depts = query.list();
System.out.println(depts.size());
for (Department dept:depts){
System.out.println(dept.getDeptName()+","+dept.getEmps().size());
}
}
建議在做連接查詢時,使用LEFT JOIN FETCH
。
8、HQL (迫切)內連接
【1】迫切內連接
INNER JOIN FETCH
關鍵字表示迫切內連接,也可以省略 INNER 關鍵字,list()
方法返回的集合中存放 Department 對象的引用,每個 Department 對象的 Employee 集合都被初始化,存放所有關聯的 Employee 對象
【2】內連接
INNER JOIN
關鍵字表示內連接,也可以省略 INNER 關鍵字,list()
方法的集合中存放的每個元素對應查詢結果的一條記錄,每個元素都是對象數組類型- 如果希望 list() 方法的返回的集合僅包含 Department 對象,可以在 HQL 查詢語句中使用 SELECT 關鍵字
三、關聯級別運行時的檢索策略
- 如果在 HQL 中沒有顯式指定檢索策略,將使用映射文件配置的檢索策略。HQL 會忽略映射文件中設置的迫切左外連接檢索策略,如果希望 HQL 採用迫切左外連接策略,就必須在 HQL 查詢語句中顯式的指定它
- 若在 HQL 代碼中顯式指定了檢索策略,就會覆蓋映射文件中配置的檢索策略