SSM框架系列: (一) Mybatis之延遲加載

延遲加載定義

百度釋義: 延遲加載(lazy load)是(也稱爲懶加載),延遲加載機制是爲了避免一些無謂的性能開銷而提出來的,所謂延遲加載就是當在真正需要數據的時候,才真正執行數據加載操作。

理解: Mybatis中, 延遲加載是 對象實體成員屬性詳情 加載的延遲. 

 

〇. 前提: 

爲說明延遲加載, 先給出如下實體模型, 訂單實體 (Order) 中包含基本屬性 (id, name, time) 和兩個成員屬性 (Product實體, Customer實體) ;

一. Mybatis加載方式分爲三種, 分別是:

    1. 直接加載: 即使用實體的任何信息時,加載全部信息, 如下圖:

    2. 侵入式延遲加載: 即需要使用延遲加載屬性詳情時, 將該對象的所有延遲加載實體屬性一次性加載, 如圖:

3. 深度延遲加載: 即真正的按需加載, 只加載真正需要使用的延遲加載項屬性, 如圖: 

二. 清楚延遲加載的分類後, 來看Mybatis中各種延遲加載策略的配置:

1. 直接加載: 當不進行任何延遲加載配置時, 即爲直接加載:

    a. 方式1: 使用select語句一次加載出所有屬性, 再使用resultMap進行相應映射 (註解方式使用@Results);

    b. 方式2: 使用select簡單查詢, 再根據查詢結果進行級聯查詢 (xml方式使用association和collection, 註解方式使用@One和@Many), 該種方式僅查詢Order基本屬性時, 會立即加載級聯加載的屬性, log記錄如下 (查詢基本屬性, 導致全部加載): 

2. 侵入式延遲加載: xml配置 (註解方式比較特殊, 請看第4條分講):

    即在Mybatis核心配置文件中增加設置標籤如下, 再使用級聯查詢, 即實現了侵入式延遲加載:

  <settings>
    <!--打開延遲加載-->
    <setting name="lazyLoadingEnabled" value="true"/>
    <!--打開浸入式延遲加載-->
    <setting name="aggressiveLazyLoading" value="true"/>
  </settings>

     但是, 此時若查詢兩個實體屬性中的任意一個時, 會導致另一個實體屬性也被加載, 這也是侵入式加載的特點: " 所有延遲加載屬性合爲一體 ", log下圖 (實際未使用3所加載的內容):

3. 深度延遲加載: xml配置 (註解方式比較特殊, 請看第4條分講):

    即在Mybatis核心配置文件中增加設置標籤如下, 再使用級聯查詢, 即實現了深度延遲加載:

  <settings>
    <!--打開延遲加載-->
    <setting name="lazyLoadingEnabled" value="true"/>
    <!--關閉浸入式延遲加載開關, 即進行深度延遲加載-->
    <setting name="aggressiveLazyLoading" value="false"/>
  </settings>

    此時, 但給我們查詢Order的其中一個實體成員屬性時, 另一個實體成員屬性不會被加載, 即實現了深度延遲加載, log日誌如下效果: 

4. Myabtis 中的註解配置:  還支持註解配置查詢語句, 其中延遲加載的配置時通過在@One或者@ many標籤中配置 fetchType = FetchType.LAZY 屬性實現, 其作用時替代Mybatis核心配置文件中的懶加載配置, 所以和 2/3 中的註解配置是替換關係, 而不是依賴關係:

配置舉例如下:  

    @Select("select * from orders")
    @Results({
            @Result(id = true,property = "id",column = "id"),
            @Result(property = "orderNum",column = "orderNum"),
            @Result(property = "orderTime",column = "orderTime"),
            @Result(property = "peopleCount",column = "peopleCount"),
            @Result(property = "orderDesc",column = "orderDesc"),
            @Result(property = "payType",column = "payType"),
            @Result(property = "orderStatus",column = "orderStatus"),
            @Result(property = "productId",column = "productId"),
            @Result(property = "product",column = "productId",javaType = Product.class,
                    one = @One(select = "com.wen.dao.IProductDao.findProductById",fetchType = FetchType.LAZY)),
            @Result(property = "product2",column = "peopleCount",javaType = Product.class,
                    one = @One(select = "com.wen.dao.IProductDao.findProductById",fetchType = FetchType.LAZY))
    })
    List<Order> findAllOrder();

    此時會有人好奇, 註解方式中並沒有侵入式延遲和深度延遲的選項, 經博主實測, Mybatis的註解方式配置延遲加載默認就是 深度延遲加載;

 

三. 延遲加載策略也的優劣和選擇:

    1. 優缺點: 

        優點:
            先查詢基本屬性, 加快了響應速度, 當需要時纔去加載實體成員屬性內容
        缺點:
            增加了查詢次數, 當大量查詢時, 降低了數據庫的性能

    2. 選擇:

    不使用場景: 深度理解延遲加載的優缺點後, 便可以根據需求進行選擇, 當查詢數據量大, 且頻繁查詢成員實體屬性時, 使用延遲加載是不合適的, 吃此時會增加數據庫的查詢次數, 從而導致數據庫性能消耗;

    使用場景: 而當查詢數據量小, 或者查詢時幾乎很少但是可能會用到成員實體屬性時, 選用延遲加載可以避免多表聯查或者大量級聯查詢, 屬於一種數據庫代碼級別的的性能優化; 

 轉載請標明出處: 划船一哥

 

 

 

 

 

 

 

 

 

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