1. 程式人生 > >【Mybatis架構】 延遲載入

【Mybatis架構】 延遲載入

       在上一篇部落格中,我們提到過有關於Mybatis輸出對映中resultMap能夠實現延遲載入的事,然而真的是所有的resultMap都能實現延遲載入還是咋地啊?現在我們就來對那一句話做一下闡述和例項說明。

一、首先我們要知道什麼是延遲載入?

       延遲載入機制是為了避免一些無謂的效能開銷而提出來的,所謂延遲載入就是當在真正需要資料的時候,才真正執行資料載入操作;可以簡單理解為,只有在使用的時候,才會發出sql語句進行查詢;延遲載入的有效期是在session開啟的情況下,當session關閉後,會報異常。當呼叫load方法載入物件時,返回代理物件,等到真正用到物件的內容時才發出sql語句。

總結:需要查詢關聯資訊時,使用mybatis延遲載入特性可有效的減少資料庫壓力,首次查詢只查詢主要資訊,              關聯資訊等使用者獲取時再載入。我們已知的除了hibernate,還有我們的Mybatis。

二、實戰演練場:

(1)需求:還以我們的上面兩篇文章的電商專案查詢訂單資訊為例,這次,我們以訂單資訊為主要查詢表,然後關聯查詢對應的使用者資訊。那什麼是延遲載入呢,就是我們預設先只查詢訂單資訊,當我們需要客戶資訊的時候呢,我們再去關聯查詢使用者資訊。這就是延遲載入了。

(2)pojo類的設計:

首先是訂單類:

public class Orders {
    private Integer id;
    private Integer userId;
    private String number;
    private Date createtime;
    private String note;
    private User user;
    //getter、setter
}

使用者資訊類:
public class User {
    private int id;
    private String username;
    private int sex;
    private Date birthday;
    private String address;
    //getter、setter
}

再就是我們Mapper對映檔案離間對resultMap的定義:
<resultMap type="com.ssm.mybatis.po.Orders" id="selectOrderUserLazyLoading">
        <!-- 配置對映的訂單資訊 -->  
        <id column="id" property="id"/>
        <result column="user_id" property="userId"/>
        <result column="number" property="number"/>
        <result column="createtime" property="createtime"/>
        <result column="note" property="note"/>

        <!-- 配置對映的使用者資訊 -->
        <association property="user" javaType="com.ssm.mybatis.po.User" 
             select="com.ssm.mybatis.mapper.UserMapper.findUserById" column="user_id">           
        </association>
    </resultMap>


在這裡,注意我們的配置對映的對映資訊裡面有一個select屬性,這裡實現的就是我們的延遲載入,後面就是我們定義的查詢使用者資訊的Mapper的名稱空間,也可以說是一個指向。

配置檔案裡面statement對resultMap的呼叫配置:
<select id="selectOrderUserLazyLoading" resultMap="OrderUserLazyLoadingResultMap" >
        select * from orders
</select>

接下來,我們定義一個mapper介面進行測試:

public interface OrdersMapper{
    List<Orders> findOrderUserLazyLoading() throws Exception;
}

測試:
@Test
public void selectOrderUserLazyLoading(){
    SqlSession session=sqlSessionFactory.openSession();
    OrdersMapperCustom ordersMapperCustomMapper=session.getMapper(OrdersMapperCustom.class);
    try {
        List<Orders> list=ordersMapperCustomMapper.findOrderUserLazyLoading();//查詢訂單資訊
        if (list!=null) {//此處有斷點
                System.out.println(list.get(0).getUser().getUsername());//查詢第一個訂單的使用者資訊
        }
    } catch (Exception e) {//此處有斷電
        e.printStackTrace();
    }
}
在上面的測試程式碼裡面,我們執行斷點查詢,分別在if和catch上打一個端點,看tomcat的日誌資訊


大家可以看到,當我們執行到第一個斷點的時候,這裡mybatis只發出一條查詢訂單資訊的sql去查詢所有的訂單資訊。接下來,我們繼續往下走:


大家看到了,當我們執行到想要獲取第一個訂單的使用者資訊時,它又發出了另一條根據id查詢使用者資訊的sql,也就是說,當我們需要呼叫使用者資訊的查詢方法時,它才會才會去執行查詢,這也就是我們所說的延遲載入,也叫做懶載入。大家可以很明顯的看到,在這裡我們使用的association來實現的延遲載入,其使用collection也一樣,至於使用association和collection有什麼區別呢,前面我們也介紹過,association是將關聯資訊對映到一個pojo物件中,而collection是將關聯訊息對映到list結合中,就這麼簡單的理由

三、如何配置Mybatis延遲載入(懶載入)

      首先我們要知道,Mybatis預設是不支援執行延遲載入(懶載入)的,這需要我們手動去配置,去開啟開關。而我們可以總結一下,但我們需要設定開啟二級快取的時候,我們首先需要在Mybatis全域性配置檔案也就是我們的sqlMapConfig.xml中去設定開啟二級快取,然後再去每個具體mapper對映檔案中去確認本對映檔案開啟二級快取,也就是所有的全域性性的功能或者是效能配置總閥門都在全域性配置檔案中的。所以我們是否開啟延遲載入的這一項功能也是在sqlMapConfig.xml中進行配置:

<settings>
   <setting name="lazyLoadingEnabled" value="true"/><!--延遲載入/懶載入-->
   <setting name="aggressiveLazyLoading" value="false"/><!--積極載入/預載入-->
</settings>
然後如何在禁止懶載入的配置就不用再介紹了吧。

另外呢,通過看師哥師姐的部落格以及外面人的介紹,mybatis的全域性配置檔案中的標籤是有先後順序的,按序分別是:properties、settings、typeAlliases、typeHandlers、objectFactory、plugins、environments、mappers。究竟是為什麼呢,為了探究這個問題,我故意使用原生的mybatis(不與spring整合)配錯一個,結果真的如是個所說,報錯:

"元素型別為configuration的內容必須匹配(properties?,settings?,typeAliases?,typeHandlers?……"

四、總結:

       以上,就是我們mybatis實現延遲載入的一個簡單介紹,那現在回答剛開頭時問的問題,是所有的resultMap都能實驗延遲載入嗎?答案是:mybatis中能實現延時載入的是resultMap,彈死不是所有的resultMap都必須實現延時載入,我們利用的是resultMap裡面的association和collection來實現的延遲載入。另外畢竟小編研究mybatis時間不長,難免有所疏漏,若有不足,還請各位指正,必及時修改。