Hibernate的查詢優化、抓取策略
敘:在hibernate中存在類級別查詢和關聯級別查詢兩種,前一個是對一對多關係情況下使用的,後一個是對多對一關係情況下使用的,詳細的請看下面的筆記;
Hibernate查詢優化、抓取策略
延遲載入(lazy載入)先獲取到的是索要查詢的資料的代理物件,當真正使用到該物件中的資料的時候,才會傳送SQL語句,這種機制是Hibernate框架提升效能的方式之一
類級別查詢
類級別查詢是指只查詢一個類的資料,並不牽涉關聯類的資料查詢,類級別查詢只有load()、get()兩個查詢方法,get()查詢是即查即得型別的,load()查詢是延遲載入(懶載入)型別的,執行到查詢語句時並不會立即查詢,而是執行到使用這個查詢語句查詢的結果才會執行查詢語句,get()方法沒有任何查詢策略,load()方法需要策略進行配置,此配置只需要在此類的對映檔案中的class標籤中設定一個lazy屬性,這個屬性只有false、true(預設);
以下是get()、load()查詢的使用;
@Test
public void demo1(){
Session session = HibernateUtils.openSession();
Transaction bt = session.beginTransaction();
//Customer cust = session.get(Customer.class, 2l);
Customer cust = session.load(Customer.class, 2l);
System.out.println(cust);
bt.commit();
}
兩個方法,在使用方面並沒有什麼區別,而且如果直接執行demo的話並不會看的出來結果,要想看到結果需要在get()/load()行與列印輸出那行各打一個斷點,然後使用debug來進行檢視;
會發現,程式碼執行到load()方法那一行時並不會有查詢語句出現,當執行到列印那一行時也不會有任何反應,但是一旦資料有事務提交後就會使用關聯的session進行資料庫查詢,載入資料,所查詢的東西完全打印出來;但是如果是get()方法的demo的話,當執行到列印那一行的時候就會出現查詢語句進行查詢,當有事務提交時就會打印出來查詢的結果;
在hibernate中有一個查詢策略的,就是關於類級別的查詢查略,同樣在實體類的對映檔案中進行配置,配置如下程式碼所示:
<hibernate-mapping package="com.java.domain" >
<class name="Customer" table="cst_customer" lazy="true" >
在對映檔案的中的class標籤中,使用lazy屬性,這個翻譯過來就是懶,對應的是load()方法的別稱–懶載入;其屬性值只有false、true(預設值)這兩個,true就是允許延遲載入(懶載入),false就是不使用懶載入,在使用false屬性值配置的情況下使用load()方法是不會起到延遲載入的效果的,這時的load()方法和get()方法沒有任何差別;
實驗方法:
把lazy屬性設定成false,然後debug執行一遍load()方法的demo,檢視執行到列印、事務提交這兩個點的程式碼輸出情況,與不編寫lazy屬性時(其實lazy屬性對get()方法沒有任何影響,這樣做是為了避嫌)get()方法的debug結果;
注意:
上面提到,load()方法懶載入是使用關聯的session進行資料庫查詢並載入資料的,也就是說當關聯的session關閉後查詢到的代理物件也不存在了,查詢也不存在了,程式碼如下所示:
@Test
/*
* 錯誤程式碼演示:關聯的session被銷燬,查詢終結
*/
public void demo2(){
Session session = HibernateUtils.openSession();
Transaction bt = session.beginTransaction();
Customer cust = session.load(Customer.class, 2l);
bt.commit();
session.close();
System.out.println(cust);
}
session被銷燬後這個session中所夾帶的或者說所代表的資料已將被銷燬,當再次呼叫這個session所關聯的資料時會報如下圖所示的錯:
結論:
為了提高效率,儘量使用load()方法;
關聯級別查詢
注意:關聯級別查詢在學習時比較拗腦^_^沒錯,就是拗腦,表述不清楚的地方還望海涵,多讀幾遍會清晰很多
關聯級別查詢是指,所要查詢資料中包含這個類A的資料以及與這類A相關聯類B的資料,即,查詢的資料包含關聯類資料;
關聯級別查詢分為集合查詢和關聯屬性查詢兩種,集合查詢就是以查詢類為主,在查詢類的檔案中進行設定相應的配置,關聯屬性查詢是指在關聯類中設定相應的配置;
在類級別查詢中我們瞭解了lazy屬性,因為類級別查詢不涉及到多個類的關聯查詢,因此不需要考慮集合查詢的策略(抓取策略),而關聯級別查詢則需對查詢的類載入問題進行配置;
集合查詢策略
集合查詢即是指一對多關係的情況下使用集合的查詢策略,所使用的屬性及其屬性值、配置位置、程式碼展示以及總結:
屬性名:屬性值
Lazy屬性:
屬性值------------ | 備註 |
---|---|
true | 延遲載入,懶載入(預設) |
false | 立即載入 |
extra | 極其懶惰,查詢的結果和懶載入效果類似,區別:如果只獲得集合的size值,只需要查詢集合的size(count語句),使用這個配置是比較方便的,但一般情況下最好還是不用此配置; |
fetch屬性:(抓取策略屬性)
屬性值------------ | 備註 |
---|---|
select | 單表查詢載入(預設) |
join | 使用多表查詢載入集合 |
subselect | 使用子查詢載入集合:根據類A的多個Customer物件查詢與之對應關聯的所有LinkMan物件的資訊;只有查詢多個Customer物件的關聯物件資料時才會使用subselect配置,當只查詢一個Customer物件的關聯物件資料時其效果和select的配置效果一樣; |
這些屬性的配置位置:在類的對映檔案中set標籤中進行設定;
配置程式碼展示:
/*
*一般的抓取快取策略demo:
*/
@Test
public void demo1(){
Session session = HibernateUtils.openSession();
Transaction bt = session.beginTransaction();
Customer cust = session.get(Customer.class, 2l);
System.out.println(cust);
bt.commit();
}
對應的對映檔案配置:
子查詢(subselect查詢集合方式)demo程式碼和一般的不太一樣,因此拎出來單獨記錄;
/*
*子查詢的Demo
*/
@Test
/*
* 關聯查詢:
* fetch:subselect
* lazy:true
*/
public void demo3(){
Session session = HibernateUtils.openSession();
Transaction bt = session.beginTransaction();
String hql = "from Customer";
Query custs = session.createQuery(hql);
List<Customer> list = custs.list();
for (Customer customer : list) {
System.out.println(customer.getLinkMens());
System.out.println(customer.getLinkMens().size());
}
bt.commit();
}
對映檔案配置:
總結/注意:
- fetch的作用:控制抓取關聯物件的時候傳送的SQL語句的格式;
- lazy的作用:控制查詢其關聯物件的時候是否採用延遲載入;
- 當fetch設定成多表查詢時(join),lazy不論設定什麼值都是無效的;
關聯屬性查詢策略
關聯查詢即是指多對一關係的類的對映檔案進行配置,所使用的屬性及其屬性值、配置位置、程式碼展示以及總結:
Lazy屬性:
屬性值 | 備註 |
---|---|
proxy | 由關聯他的類A的類級別載入策略決定; |
false | 立即載入 |
fetch屬性:
屬性值 | 備註 |
---|---|
select | 單表查詢載入 |
join | 使用多表查詢載入集合 |
屬性配置位置:在類的對映檔案中的標籤中進行設定
Demo:
@Test
public void demo4(){
Session session = HibernateUtils.openSession();
Transaction bt = session.beginTransaction();
LinkMan linkMan = session.get(LinkMan.class, 2l);
Customer customer = linkMan.getCustomer();
System.out.println(customer);
bt.commit();
}
對映檔案配置展示:
注意:
- 需要注意當使用懶載入的proxy屬性值時,意為由關聯這個B物件的A物件的類級別載入策略決定,注意,是A物件的類級別載入策略,就是寫在class標籤中進行配置的;
優化查詢總結:
為了提高效率,fetch一般使用預設值select,lazy使用預設值true,即,全部使用預設值即可;
No-Session問題解決辦法:
No-session 問題導致的原因是用到的資料物件所關聯的session物件已經被清除,session物件所關聯的資料需要在web、service、dao層中進行傳遞,最終查詢的資料結果需要放到頁面中展示給使用者,因此要擴大session的作用範圍,所使用的技術就是過濾器(filter),具體解決思路如下:
既是,在經過過濾器時就會建立一個session,使用這個session直到放行完成所有操作後在進行清理session並提交事務;
pass:學完了查詢優化和抓取策略基本上hibernate的入門什麼的已經算是完成了,但是對於hibernate框架來說這只是皮毛,真正的學習是往後的研究探索,希望大家能有所建樹對於此框架的學習~一起加油吧^_^
# 《本章完》