敘:在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框架來說這只是皮毛,真正的學習是往後的研究探索,希望大家能有所建樹對於此框架的學習~一起加油吧^_^
# 《本章完》