Hibernate(八):檢索策略
Hibernate的Session在載入一個Java物件時,可以將與這個物件相關聯的其他物件都載入到快取中,以便程式及時呼叫。但在一些情況下,不需要載入太多沒有用的物件到快取中去,這會增加快取的負荷和訪問資料庫的次數,所以為了合理的利用快取。Hibernate提供了幾種檢索策略
作用域
1.檢索策略的作用域分為: 類級別和關聯級別。
- 類級別的作用域在檢索資料時,檢索的物件只包含一個數據,不涉及與該類有關的其他物件
- 關聯級別的作用域檢索的資料包含相關聯的多個類的物件。例如:Customer物件與Order物件存在關聯關係,檢索一個Customer物件,還會涉及到與之關聯的Order物件
2. 作用域對比:
檢索策略的作用域 | 可選的檢索策略 | 預設的檢索策略 | 執行時行為受影響的檢索方法 |
類級別 | 立即檢索 延遲檢索 |
延遲檢索 | 僅影響Session的load()方法 |
關聯級別 | 立即檢索 延遲檢索 迫切左外連線檢索 |
延遲檢索 | 影響Session的load()和get()方法,以及Query的API會忽略 對映檔案中設定的迫切左外連線檢索策略 |
Hibernate的檢索策略
檢索策略分為三種:立即檢索,延遲檢索,左外連線檢索
1.立即檢索
(1) 採用立即檢索策略,會把被檢索的物件,以及和這個物件關聯額一對多物件都載入到快取中。Session的get()方法就是採用的立即檢索的策略
(2) 無論 <class> 元素的 lazy 屬性是 true 還是 false, Session 的 get() 方法及 Query 的 list() 方法在類級別總是使用立即檢索策略
若 <class> 元素的 lazy 屬性為 true 或取預設值, Session 的 load() 方法不會執行查詢資料表的 SELECT 語句, 僅返回代理類物件的例項, 該代理類例項有如下特徵:
- 由 Hibernate 在執行時採用 CGLIB 工具動態生成
- Hibernate 建立代理類例項時, 僅初始化其 OID 屬性
- 在應用程式第一次訪問代理類例項的非 OID 屬性時, Hibernate 會初始化代理類例項
(3)優點:頻繁使用的物件會被載入到快取中,程式呼叫方便,很及時
缺點:佔用的記憶體過多 ,而且資料庫訪問次數也會很頻繁,效率低下
2.延遲檢索
(1)採用延遲檢索策略,就不會載入關聯物件的內容。直到第一次呼叫關聯物件時,才會載入關聯物件。在不涉及關聯類操作時,延遲檢索策略只使用於Session的load()方法。涉及關聯類操作時,延遲檢索策略也能夠適用於get,list等操作
(2)類級別操作:只加載類的OID不載入類的其他屬性,只用當第一次訪問其他屬性時,才會回訪資料庫去載入內容。
關聯級別操作:只加載類本事,不載入關聯類。直到第一次呼叫關聯物件,才去載入關聯物件。
(3) 如果需要指定延遲載入策略,需要在配置檔案設定<class>的lazy=true,<set>的lazy=true或extra(增強延遲),<many-to-one>的lazy=proxy和no-proxy
(4)延遲檢索和增強延遲檢索
->在延遲檢索(lazy 屬性值為 true) 集合屬性時, Hibernate 在以下情況下初始化集合代理類例項 :
- 應用程式第一次訪問集合屬性: iterator(), size(), isEmpty(), contains() 等方法
- 通過 Hibernate.initialize() 靜態方法顯式初始化
- 當程式第一次訪問 orders 屬性的 iterator() 方法時, 會導致 orders 集合代理類例項的初始化
- 當程式第一次訪問 order 屬性的 size(), contains() 和 isEmpty() 方法時, Hibernate 不會初始化 orders 集合類的例項, 僅通過特定的 select 語句查詢必要的資訊, 不會檢索所有的 Order 物件
(5)優點:由程式決定載入哪些類和內容,而不必全部載入,避免記憶體的大量佔用和資料庫的頻繁訪問
缺點:在Session關閉後,就不能訪問關聯類物件。需要確保Session一直處於開啟開啟狀態,呼叫關聯物件之後關閉Session物件
3.左外連線檢索
(1)採用左外連線檢索,能夠使用SQL的外連線查詢,將需要載入的關聯物件載入在快取中
(2)<set>fetch設定為join,<many-to-one>fetch設定為join
(3) 優點:對應用程式完全透明,不管物件處於持久化狀態,還是遊離狀態,應用程式都可以方便的從一個物件導航到與它關聯的物件。使用了外連線,select語句數目減少
缺點:可能會載入應用程式不需要訪問的物件,會浪費許多記憶體空間。複雜的資料庫表連線也會檢索效能。
4.三種檢索的執行機制
5.比較三種檢索策略
一對多和多對多使用的檢索策略
1.在對映檔案中, 用 <set> 元素來配置檢索策略. <set> 元素屬性:
(1)lazy: 主要決定 orders 集合被初始化的時機. 即到底是在載入 Customer 物件時就被初始化, 還是在程式訪問 orders 集合時被初始化
(2)fetch: 取值為 “select” 或 “subselect” 時, 決定初始化 orders 的查詢語句的形式; 若取值為”join”, 則決定 orders 集合被初始化的時機(若把 fetch 設定為 “join”, lazy 屬性將被忽略)
-> 當fetch屬性為“subselect”時:
- 假定Session快取中有n個orders集合代理例項沒有被初始化,Hibernate能夠通過帶子查詢的select語句,來批量初始化n個orders的集合代理類例項
- batch-size屬性將會被忽略
- 子查詢的select語句為查詢Customer表OID的SELECT語句
- 假定 Session 快取中有 n 個 orders 集合代理類例項沒有被初始化, Hibernate 能夠通過帶子查詢的 select 語句, 來批量初始化 n 個 orders 集合代理類例項
- batch-size 屬性將被忽略
- 子查詢中的 select 語句為查詢 CUSTOMERS 表 OID 的 SELECT 語句
(3)lazy屬性和fetch屬性的使用:
(4) batch-size 屬性:用來為延遲檢索策略或立即檢索策略設定批量檢索的數量. 批量檢索能減少 SELECT 語句的數目, 提高延遲檢索或立即檢索的執行效能.
2.<many-to-one>元素的屬性配置檢索策略:
(1)lazy屬性和fetch屬性的使用:
若fetch屬性為“join”,那麼lazy屬性將被忽略
3.總結-對映檔案中用於設定檢索策略的幾個屬性