Hibernate之檢索策略

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

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章