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();
    }

映射文件配置:
子查詢文件配置

總結/注意:

  1. fetch的作用:控制抓取關聯對象的時候發送的SQL語句的格式;
  2. lazy的作用:控制查詢其關聯對象的時候是否採用延遲加載;
  3. 當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),具體解決思路如下:
no-session問題解決辦法思路圖
既是,在經過過濾器時就會創建一個session,使用這個session直到放行完成所有操作後在進行清理session並提交事務;


pass:學完了查詢優化和抓取策略基本上hibernate的入門什麼的已經算是完成了,但是對於hibernate框架來說這只是皮毛,真正的學習是往後的研究探索,希望大家能有所建樹對於此框架的學習~一起加油吧^_^
# 《本章完》
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章