1.概述
檢索數據時的2個問題:
-
不浪費內存:當Hibernate從數據庫中加載Customer對象時,如果同時加載所有關聯的Order對象,而程序僅僅需要訪問Customer對象,那麼關聯的Order對象就白白浪費了許多內存
-
更高的查詢效率:發送儘可能少的SQL語句
2.類級別的檢索策略
-
包括立即檢索和延遲檢索,默認爲延遲檢索
-
立即檢索:立即加載檢索方法指定的對象
-
延遲檢索:延遲加載檢索方法指定的對象
-
-
類級別的檢索策略可以通過<class>元素的lazy屬性進行設置
-
如果程序加載一個對象的目的是爲了訪問它的屬性,可以採取立即檢索
-
如果僅僅是爲了獲得它的引用,可以採用延遲索引
-
-
無論<class>元素的lazy屬性是true還是false,Session的get()方法和Query的list()方法在類級別總是使用立即檢索策略
<class name="Order" table="ORDERS" lazy="true">具體內容省略...</class>
3.一對一和多對多的檢索策略
-
在映射文件中,用<set>元素來配置一對多關聯及多對多管理關係。<set>元素有lazy和fetch屬性
-
lazy:主要決定orders集合被初始化的實際
-
fetch:取值爲“select”或“subselect”時,決定初始化orders的查詢語句的形式;若取值爲“join”,則決定orders集合被初始化的時機
-
若把fetch設置爲“join”,lazy屬性將被忽略
-
<set>元素的batch-size屬性:用來爲延遲檢索策略或理解檢索策略設定批量檢索的數量
-
lazy屬性(默認:true) | fetch(默認:select) | 檢索策略 |
---|---|---|
true | select | 延遲檢索 |
false | select | 立即檢索 |
extra | select | 加強延遲檢索 |
true,false或extra | select | select查詢:select * from orders where customer_id in(1,2,3,4) |
true,false或extra | subselect | 子查詢:select * from orders where customer_id in(select id from customers) |
true | join | 採用迫切左外連接策略 |
(1)延遲檢索
-
Hibernate在以下情況下初始化集合代理類實例
-
應用程序第一次訪問集合屬性,iterator(),size(),isEmpty(),contains()等方法
-
通過Hibernate.initialize()靜態方法顯式初始化
-
(2)增強延遲檢索
-
進一步延遲Customer對象的Orders集合代理實例的初始化時機
-
當程序第一次訪問orders屬性的iterator()方法,會導致orders集合代理類實例的初始化
-
當程序第一次訪問order屬性的size(),contains()和isEmpty()方法時,Hibernate不會初始化orders集合類的實例,僅通過特定的select語句查詢必要的信息。比如:select count(*) from order where 條件
-
(3)<set>元素的batch-size屬性
<set> 元素有一個 batch-size 屬性, 用來爲延遲檢索策略或立即檢索策略設定批量檢索的數量. 批量檢索能減少 SELECT 語句的數目, 提高延遲檢索或立即檢索的運行性能
若batch-size設置爲3,有5條數據 select * from order where customer_id in(1,2,3) select * from order where customer_id in(4,5)
(4)迫切左外連接
-
檢索Customer對象時,會採用迫切左外連接(通過左外連接加載與檢索指定的對象關聯的對象)策略來檢索所有關聯的Order對象
-
lazy屬性將被忽略
-
Query的list()方法會忽略映射文件中配合的迫切左外連接策略,依舊採用延遲加載策略
@Test
public void testSetFetch2(){
Customer customer = (Customer) session.get(Customer.class, 1);
System.out.println(customer.getOrders().size());
}
@Test
public void testSetFetch(){
//1. 若取值爲 join. 則
//1.1 在加載 1 的一端的對象時, 使用迫切左外連接(使用左外鏈接進行查詢, 且把集合屬性進行初始化)的方式檢索 n 的一端的集合屬性
//1.2 忽略 lazy 屬性.
//1.3 HQL 查詢忽略 fetch=join 的取值
List<Customer> customers = session.createQuery("FROM Customer").list();
System.out.println(customers.size());
for(Customer customer: customers){
if(customer.getOrders() != null)
System.out.println(customer.getOrders().size());
}
}
4.多對一的檢索策略
-
<many-to-one>元素也有一個lazy屬性和fetch屬性
-
若fetch屬性爲join,那麼lazy屬性將被忽略
-
無代理延遲檢索需要增強持久化類的字節碼才能實現
-
lazy屬性(默認:proxy) | fetch屬性(默認:select) | 檢索策略 |
---|---|---|
proxy | select | 延遲檢索 |
no-proxy | select | 無代理延遲檢索 |
false | select | 立即檢索 |
proxy | join | 迫切左外連接 |
<hibernate-mapping package="com.yfy.hibernate.strategy">
<class name="Order" table="ORDERS">
<id name="orderId" type="java.lang.Integer">
<column name="ORDER_ID" />
<generator class="native" />
</id>
<property name="orderName" type="java.lang.String">
<column name="ORDER_NAME" />
</property>
<many-to-one
name="customer" class="Customer"
column="CUSTOMER_ID"
lazy="false"
fetch="join"></many-to-one>
</class>
</hibernate-mapping>
public class Customer {
private Integer customerId;
private String customerName;
private Set<Order> orders = new HashSet<>();
}