Mybatis懶加載

什麼叫懶加載?

顧名思義,懶加載就是因爲偷懶了,懶得加載了,只有使用的時候才進行加載。其實,懶加載也加延遲加載,主要以應用與Mybatis的關聯查詢,按照設置的延遲規則,推遲對延遲對關聯對象的select查詢,例如,我們在用Mybatis進行一對多的時候,先查詢出一方,當程序需要多方數據時,mybatis會再次發出sql語句進行查詢,減輕了對我們數據庫的壓力。Mybatis的延遲加載,只對關聯對象有延遲設置。

加載時機

Mybatis根據對關聯對象查詢的select語句的自信時機,分爲三種類型:直接加載、侵入式延遲加載與深度延遲加載。

  • 直接加載:執行完對主加載對象的 select 語句,馬上執行對關聯對象的 select 查詢。
  • 侵入式延遲: 執行對主加載對象的查詢時,不會執行對關聯對象的查詢。但當要訪問主加載對象的詳情屬性時,就會馬上執行關聯對象的select查詢。
  • 深度延遲: 執行對主加載對象的查詢時,不會執行對關聯對象的查詢。訪問主加載對象的詳情時也不會執行關聯對象的select查詢。只有當真正訪問關聯對象的詳情時,纔會執行對關聯對象的 select 查詢。

需要注意的是,延遲加載要求,對關聯對象的查詢與主加載對象的查詢必須分別進行的select語句,不能是使用多表連接所進行的select查詢。因爲多表連接查詢,其實質是對一張表的查詢,對由多個表連接後形成的一張表的查詢。會一次性將多張表的所有信息查詢出來。Mybatis中對於延遲加載設置,只對於resultMap中的collection和association起作用,可以應用到一對一、一對多、多對一、多對多的所有關聯查詢中。下面以一對多關聯關係查詢爲例,講解 MyBatis 中的延遲加載應用。

一對多的多表單獨查詢方式

以Team和Player爲例,將這兩個bean類中的。一個Team對應多個Player。

對應的TeamMappper.xml文件

<!--根據team的id查找player-->
<select id="selectPlayerByTeamId" resultType="Player">
    select id,name from t_player WHERE tid=#{id}
</select>

<!--關聯屬性映射關係-->
<!--集合的數據來自select查詢,該查詢的條件是selectTeamByIdAlone查詢出的id-->
<resultMap id="teamMapAlone" type="Team">
    <id column="id" property="id"/>
    <result column="name" property="name"/>
    <collection property="playerList" ofType="Player" select="selectPlayerByTeamId" column="id"/>
</resultMap>


<select id="selectTeamByIdAlone" resultMap="teamMapAlone">
    SELECT id,name FROM t_team where id=#{id}
</select>

在TeamDao中添加下面方法:

Team selectTeamByIdAlone(int id);

在測試類中添加下面方法:

@Test
public void selectTeamByIdAlone() {
    Team team = teamDao.selectTeamByIdAlone(1);

}

執行之後,可以看到控制檯中分兩次發出了sql語句分別查詢t_team和t_player表。

開啓侵入式延遲

在mybatis-config.xml配置文件中配置

<!--全局參數設置-->
<settings>
    <!--延遲加載總開關-->
    <setting name="lazyLoadingEnabled" value="true"/>
    <!--侵入式延遲加載開關-->
    <!--3.4.1版本之前默認是true,之後默認是false-->
    <setting name="aggressiveLazyLoading" value="true"/>
</settings>

lazyLoadingEnabled表示延遲加載的總開關,如果將其設置爲false,即使侵入式開關設置爲true也不會生效。
aggressiveLazyLoading表示侵入式延遲加載開關,在3.4.1版本之前默認是true,之後默認是false。

將以上內容配置好之後,再執行上面測試類方法的時候,就會發現在控制檯中只發出了一條查詢t_team的sql語句,這是因爲我們開啓了侵入式延遲加載開關,在java程序中並未訪問Team中的任何屬性,所以mybatis不會去查詢其關聯的player對象數據。

修改測試方法如下:

@Test
public void selectTeamByIdAlone() {
    Team team = teamDao.selectTeamByIdAlone(1);
    System.out.println(team.getName());
}

再次執行上面方法之後就會看到控制檯中發出兩條SQL語句分別查詢t_team和t_player,這是因爲在java程序中訪問了Team的屬性name,所以mybatis會將其關聯的player對象數據查詢出來。

開啓深度延遲加載

修改mybatis-config.xml文件:
開啓總開關,將aggressiveLazyLoading關閉即可

<!--全局參數設置-->
<settings>
    <!--延遲加載總開關-->
    <setting name="lazyLoadingEnabled" value="true"/>
    <!--侵入式延遲加載開關-->
    <!--3.4.1版本之前默認是true,之後默認是false-->
    <setting name="aggressiveLazyLoading" value="false"/>
</settings>

繼續執行上面的測試方法,可以看到控制檯中只打印了一條查詢t_team表的sql語句。

修改測試方法如下:

 @Test
public void selectTeamByIdAlone() {
    Team team = teamDao.selectTeamByIdAlone(1);
    System.out.println(team.getName());
    System.out.println(team.getPlayerList().size());
}

執行上面測試方法之後,可以看到控制檯中打印了兩條sql語句分別查詢t_team和t_player,這說明當開啓深度延遲後,只要代碼中不使用player相關的數據,mybatis就不會進行sql查詢,只有當真正使用的時候纔會去發出sql語句查詢。

在單個resultMap中使用延遲加載

上面都是通過在mybatis.xml文件中統一配置的深度延遲加載,倘若只希望某些查詢支持深度延遲加載的話可以在resultMap中的collection或association添加fetchType屬性,配置爲lazy之後是開啓深度延遲,配置eager是不開啓深度延遲。fetchType屬性將取代全局配置參數lazyLoadingEnabled的設置

懶加載總結

通過上面的示例可以發現深度加載的方式最爲懶,通過這種方式可以讓mybatis在執行查詢的時候減少sql的查詢從而提高程序的執行效率,但是並不是所有場景下使用懶加載都能提高效率,有些場景比如在查詢一對多時,就需要將一方和多方都查詢出來,這樣的話開啓懶加載反而有可能會拖慢程序的執行效率。這個在以後深入學習mybatis的時候再做討論。

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