1. 程式人生 > >Mybatis 延遲載入詳解

Mybatis 延遲載入詳解

MyBatis中的延遲載入,也稱為懶載入,是指在進行關聯查詢時,按照設定延遲規則推遲對關聯物件的select查詢。延遲載入可以有效的減少資料庫壓力。

注意:MyBatis的延遲載入只是對關聯物件的查詢有延遲設定,對於主載入物件都是直接執行查詢語句的。

一、關聯物件載入時機

MyBatis根據對關聯物件查詢的select語句的執行時機,分為三種類型:直接載入、侵入式載入與深度延遲載入

  • 直接載入:執行完對主載入物件的select語句,馬上執行對關聯物件的select查詢。
  • 侵入式延遲:執行對主載入物件的查詢時,不會執行對關聯物件的查詢。但當要訪問主載入物件的詳情時,就會馬上執行關聯物件的select查詢。即對關聯物件的查詢執行,侵入到了主載入物件的詳情訪問中。也可以這樣理解:將關聯物件的詳情侵入到了主載入物件的詳情中,即將關聯物件的詳情作為主載入物件的詳情的一部分出現了。
  • 深度延遲:執行對主載入物件的查詢時,不會執行對關聯物件的查詢。訪問主載入物件的詳情時也不會執行關聯物件的select查詢。只有當真正訪問關聯物件的詳情時,才會執行對關聯物件的select查詢。

注意:延遲載入的應用要求,關聯物件的查詢與主載入物件的查詢必須是分別進行的select語句,不能是使用多表連線所進行的select查詢。因為,多表連線查詢,其實質是對一張表的查詢,對由多個表連線後形成的一張表的查詢。會一次性將多張表的所有資訊查詢出來。

二、直接載入

1.主配置檔案(Mybatis.xml)

全域性屬性lazyLoadingEnabled的值只要設定為false,那麼,對於關聯物件的查詢,將採用直接載入。即在查詢過主載入物件後,會馬上查詢關聯物件。

lazyLoadingEnabled的預設值為false,即直接載入。

<settings>
    <!-- 延遲載入總開關 -->
    <setting name="lazyLoadingEnabled" value="false"/>
</settings>
  • 1
  • 2
  • 3
  • 4
  • 5

2.mapper對映檔案

<mapper namespace="com.hcx.dao.IMinisterDao">

    <select id="selectCountryById" resultType="Country">
        select
cid,cname from country where cid=#{cid} </select> <resultMap type="Minister" id="ministerMapper"> <id column="mid" property="mid"/> <result column="mname" property="mname"/> <association property="country" javaType="Country" select="selectCountryById" column="countryId"/> </resultMap> <select id="selectMinisterById" resultMap="ministerMapper"> select mid,mname,countryId from minister where mid=#{mid} </select> </mapper>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

3.測試類:

當程式執行到斷點處語句時,不僅對country表進行了查詢,對minister表也同時進行了查詢。

public class MyTest {

    private ICountryDao dao;
    private SqlSession session;

    @Before
    public void setUp(){
        session = MyBatisUtils.getSqlSession();
        dao = session.getMapper(ICountryDao.class);
    }

    @After
    public void tearDown(){
        if(session!=null){
            session.close();
        }
    }

    @Test
    public void test01(){       
        Country country = dao.selectCountryById(2);
        //此處加斷點
        System.out.println(country);
        System.out.println(country.getMinisters().size());
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27

三、深度延遲載入

修改主配置檔案的,將延遲載入開關lazyLoadingEnabled開啟(置為true),將侵入式延遲載入開關aggressiveLazyLoading關閉(置為false)。

<settings>
    <!-- 延遲載入總開關 -->
    <setting name="lazyLoadingEnabled" value="true"/>
    <!-- 侵入式延遲載入開關 -->
    <setting name="aggressiveLazyLoading" value="false"/>
</settings>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

此時,只有當代碼執行到輸出Minister物件詳情時,底層才執行select語句對minister表進行查詢。

四、侵入式延遲載入

修改主配置檔案的,將延遲載入開關lazyLoadingEnabled開啟(置為true),將侵入式延遲載入開關aggressiveLazyLoading也開啟(置為true,預設為true)。

<settings>
    <!-- 延遲載入總開關 -->
    <setting name="lazyLoadingEnabled" value="true"/>
    <!-- 侵入式延遲載入開關 -->
    <setting name="aggressiveLazyLoading" value="true"/>
</settings>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

測試類:

@Test
public void test01(){       
    Country country = dao.selectCountryById(2);
    //此處加斷點
    System.out.println(country);
    System.out.println(country.getMinisters().size());
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

當代碼執行斷點處語句時會立即查詢country表,但每查詢minister表。說明現在的延遲載入已經啟動。
當對country物件的詳情進行訪問時,對minister表也進行了查詢。因為該延遲載入策略已經將主載入物件的關聯屬性也作為主載入物件的基本資訊了,而前面已經查詢出了主載入物件的基本資訊,但其關聯物件基本資訊尚無。所以,馬上進行對minister表的查詢。
換個角度來說,該延遲策略使關聯物件的資料侵入到了主載入物件的資料中,所以稱為侵入式延遲載入。

注意:該延遲策略也是一種延遲載入,需要在延遲載入開關lazyLoadingEnabled開啟時才會起作用。若lazyLoadingEnabled為false,則aggressiveLazyLoading無論取何值,均不起作用。

五、延遲載入策略總結

延遲載入.PNG