[07] 延遲加載


如今咱們有 Author 做者類,其屬性中有 List<Book> bookList 用來表示該做者所出版的書籍。咱們配置好映射關係以後,但願在獲取到一個 Author 類時,其 bookList 的值只有當咱們在用到的時候纔會去數據庫獲取,而不是每次都給咱們所有的完整數據,這也就是MyBatis延遲加載要解決的問題:即映射集合內存在級聯時,咱們實際須要的數據少於數據庫查出來的數據。這就會形成數據庫多查出來的數據派不上用場,同時也加大了數據庫負擔。

咱們在提到 MyBatis 的內聯時,必然會涉及到的就是兩個元素 association 和 collection,在以前的闡述中咱們也說過,對於內聯查詢的方式有一種利用到了 select 屬性,也便是咱們延遲加載的主人公。咱們說使用 select 其實是將SQL語句分紅了兩部分單獨執行,而不是採用聯表查詢的SQL,也正是這樣,能讓咱們實現延遲加載。

在MyBatis中實現延遲加載有兩種方式,若是你但願全局開啓延遲加載,那麼你須要在mybatis-config.xml全局配置文件的<settings>中加入下面這兩個配置:
<!--開啓全局延遲加載(懶加載)-->
<setting name="lazyLoadingEnabled" value="true" />
<!--任何方法調用均加載該對象全部屬性-->
<setting name="aggressiveLazyLoading" value="false"/>

若是你並不想全局開啓,只是針對某個類的某些屬性進行延遲加載開啓,那麼則須要你在 resultMap 中的 association 或 collection 設置屬性值 fetchType="lazy",以下示例:
<association fetchType="lazy" property="author" column="author_id" javaType="dulk.learn.mybatis.pojo.Author" select="findAuthorById"/>

剛纔咱們提到了做者和書之間的一對多關係,下面咱們就來以此爲例看下相關的代碼和配置。

Author類:
public class Author {
    private long id;
    private String name;
    private int age;
    private List<Book> bookList;

    //... getter and setter
}

Dao接口:
public interface AuthorDao {
    Author findAuthorById(long id);
    Book findBookByAuthorId(long authorId);
}

mapper.xml:
<mapper namespace="dulk.learn.mybatis.dao.AuthorDao">

    <resultMap id="authorResultMap" type="dulk.learn.mybatis.pojo.Author">
        <id property="id" column="id"/>
        <result property="name" column="name" />
        <result property="age" column="age" />
        <!--採用select形式,設定fetchType延遲加載,column爲關聯查詢的列-->
        <collection fetchType="lazy" property="bookList" column="id" select="findBookByAuthorId" />
    </resultMap>

    <select id="findAuthorById" parameterType="long" resultMap="authorResultMap">
        SELECT *
        FROM author
        WHERE id = #{id}
    </select>

    <select id="findBookByAuthorId" parameterType="long" resultType="dulk.learn.mybatis.pojo.Book">
        SELECT *
        FROM book
        WHERE author_id = #{authorId}
    </select>

</mapper>
  • 使用select方式加載內聯屬性的數據(而非聯表查詢)
  • 設置全局延遲加載,或者局部設置 fetchType="lazy"
  • column列爲關聯查詢的列

寫個單元測試看看:
public class TestAuthor {

    @org.junit.Test
    public void testMyBatis() throws IOException {
        //讀取配置文件
        InputStream is = Resources.getResourceAsStream("mybatis-config.xml");
        //獲取工廠類
        SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(is);
        //獲取SqlSession數據庫會話對象
        SqlSession sqlSession = factory.openSession();
        //獲取Dao
        AuthorDao authorDao = sqlSession.getMapper(AuthorDao.class);

        Author author = authorDao.findAuthorById(2);
        System.out.println("-------------------------------------");
        List<Book> bookList = author.getBookList();
    }

}

以下輸出日誌,能夠看到bookList在調用時才執行了SQL語句去查詢:
Opening JDBC Connection
Created connection 1685232414.
Setting autocommit to false on JDBC Connection [com.mysql.jdbc.JDBC4Connection@64729b1e]
==>  Preparing: SELECT * FROM author WHERE id = ? 
==> Parameters: 2(Long)
<==    Columns: id, name, age
<==        Row: 2, 李四, 18
<==      Total: 1
-------------------------------------
==>  Preparing: SELECT * FROM book WHERE author_id = ? 
==> Parameters: 2(Long)
<==    Columns: id, name, price, author_id
<==        Row: 1, 小帽子歷險記, 23, 2
<==        Row: 2, 紅帽子探險記, 12, 2
<==      Total: 2
相關文章
相關標籤/搜索