延遲加載定義:
百度釋義: 延遲加載(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. 選擇:
不使用場景: 深度理解延遲加載的優缺點後, 便可以根據需求進行選擇, 當查詢數據量大, 且頻繁查詢成員實體屬性時, 使用延遲加載是不合適的, 吃此時會增加數據庫的查詢次數, 從而導致數據庫性能消耗;
使用場景: 而當查詢數據量小, 或者查詢時幾乎很少但是可能會用到成員實體屬性時, 選用延遲加載可以避免多表聯查或者大量級聯查詢, 屬於一種數據庫代碼級別的的性能優化;
轉載請標明出處: 划船一哥