標籤:遍曆 get view init sub sql語句 工具 代理 不同
一,消極式載入
1、實體類消極式載入 通過代理機制完成,由javassist類庫實現運行時代理,修改實體類的位元組碼實現了運行時代理
<class lazy="true|false">
實體層級的消極式載入預設值為true,意味實體物件是消極式載入,隻影響load方法。
<class lazy="true|false">其他查詢方式都是立即載入
2、關聯屬性消極式載入 預設情況下除了<one-to-one>之外所有的關聯屬性都是消極式載入
A、單端關聯對象<many-to-one lazy="proxy|no-proxy|false"> <one-to-one lazy="false|proxy|no-proxy">
通過javassist代理實現消極式載入
B、集合關聯對象 <set lazy="true|extra|false">
在hibernate中為實現集合關聯屬性的消極式載入,沒有使用jdk中的集合架構,它實現了一套自己的集合架構,
比如它的set集合通過PersistSet(該類實現java.util.Set介面)實現,
集合關聯屬性的lazy預設值為true,意味集合關聯屬性消極式載入。
lazy="extra"除指定集合屬性消極式載入功能外,能夠讓hibernate智能感知開發人員對關聯的集合屬性的操作類型,
hibernate會根據開發人員對集合操作類型不同執行不同的sql語句,所以建議集合關聯屬性的lazy="extra"
1 Department dept = (Department) session.get(Department.class, 10);2 3 Set<Employee> set = dept.getEmps();//擷取到關聯的集合屬性4 5 //判斷集合中元素個數是否為0 當關聯屬性lazy="true",如果我們僅僅需要判斷集合中是否元素或者僅僅需要集合中元素個數不是這些元素6 // select * from emp where deptno=?7 boolean b = set.isEmpty();8 //擷取集合中元素的個數9 int size = set.size();
1 Department dept = (Department) session.get(Department.class, 10); 2 3 Set<Employee> set = dept.getEmps();//擷取到關聯的集合屬性 4 5 //當lazy="extra"時,集合關聯屬性消極式載入,同時提供了一些功能,讓hibernate能夠智能感應開發人員對集合關聯屬性的操作類型 6 //hibernate會根據開發人員對集合屬性的操作類型不同執行不同的sql語句 7 //當開發人員執行調用集合屬性的isEmpty()方法或者size()方法時發送select count(*) from emp where deptno=? 8 //當開發人員執行遍曆操作發送select * from emp where deptno=? 9 boolean b = set.isEmpty();10 11 int size = set.size();
3、普通屬性消極式載入 編譯時間對位元組碼進行修改
<property lazy="false|proxy|no-proxy">
關聯對象的消極式載入有利於程式的運行效率,但在一些情況下會產生問題,如:消極式載入的關聯對象在session關閉後如何擷取?
- openSessionInView,把session的生命週期延長,保證在擷取關聯對象後關閉session;
- 在HQL語句中使用關鍵字fetch左外串連查詢,立即擷取主體對象和關聯對象
List list=session.createQuery("from Employee e join fetch e.dept").list(); //Employee(dept)
3. 在關聯屬性對應資訊中將fetch="join",會通過左外串連立即把關聯物件查詢出來(不建議使用)
4. 通過Hibernate工具類中initialize(Object lazyObject),立即載入關聯對象
5. Criteria擷取關聯對象,調用setFetchMode("關聯對象名",FetchMode m)將抓取方式m設定FetchMode.JOIN
二,抓取策略
關聯對象的抓取方式的設定:
<many-to-one fetch="select|join">和<one-to-one fetch="join|select">
<set fetch="select|join|subselect">
join : 以左外串連形式立即擷取關聯對象(僅僅針對get方法和load方法時有效,對HQL查詢、標準查詢無效,不推薦設定)。
select :另外發送一條查詢語句擷取關聯對象
subselect :另外發送一條查詢語句或者子查詢擷取關聯對象載入出來
三,1+n問題
什麼是1+N問題:當我們發送1條sql語句擷取主體對象的資料,假設擷取到n個主體對象,
但是需要發送額外的n條資料擷取關聯對象。
解決1+n問題:
1、關聯屬性的對應檔資訊中fetch="join",可以解決load和get方式的1+n問題(不建議)
2、使用HQL語句中關鍵字fetch,通過左外串連立即載入關聯對象,所以該操作前提,我們確實需要立即將關聯對象載入
3、使用Criteria查詢語句,通過該對象的setFetchMode(String ass,FetchMode m) 設定為FetchMode.JOIN,
這樣通過左外串連立即載入關聯對象 只需要一條sql語句
4、設定批量載入,減少查詢語句
1、在hibernate.cfg.xml中配置<property name="default.batch_fetch_size">2</property> 2、在集合關聯屬性<set batch-size="1|2|4|8|16">
單端的關聯屬性在單端對應的實體類<class batch-size="1|2|4|8|16">
5、將<set fetch="subselect">擷取關聯集合屬性時通過子查詢擷取,避免1+N問題。
6、Query對象的iterator()方法引起的1+N問題要通過二級緩衝解決
hibernate的消極式載入和抓取策略