1. 程式人生 > >SSM框架系列: (一) Mybatis之延遲載入

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. 選擇:

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

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

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