Mybatis學習系列(六)延遲加載

延遲加載其實就是將數據加載時機推遲,好比推遲嵌套查詢的執行時機。在Mybatis中常常用到關聯查詢,可是並非任什麼時候候都須要當即返回關聯查詢結果。好比查詢訂單信息,並不必定須要及時返回訂單對應的產品信息,查詢商品分類信息並不必定要及時返回該類別下有哪些產品,這種狀況一下須要一種機制,當須要查看時,再執行查詢,返回須要的結果集,這種需求在Mybatis中可使用延遲加載機制來實現。延遲加載能夠實現先查詢主表,按需實時作關聯查詢,返回關聯表結果集,必定程度上提升了效率。java

Mapper.xml映射文件

以商品類別category和商品product爲例,一個類別下能夠有多個商品,一個商品屬於一種類別。sql

編寫lazyLoadMapper.xml映射文件數據庫

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper 
    PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" 
    "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.sl.mapper.LazyLoadMapper">
        <!-- 分類信息查詢 -->
        <select id="lazyLoadTest"  resultMap="lazyLoadProductsByCategoryTest">
            select * from category where id=#{id}
        </select>
        <resultMap id="lazyLoadProductsByCategoryTest" type="com.sl.po.Category">
            <id column="id" property="Id"></id>
            <result column="name" property="Name"></result>
            <result column="remark" property="Remark"></result>
            <!-- 一個分類對應多個產品,此處使用collection -->
            <collection property="productList" ofType="com.sl.po.Product"  column="id" select="selectProductsByCategoryId"></collection>
        </resultMap>
        
        <!-- 嵌套查詢返回商品信息,延遲加載將要執行的sql -->
        <select id="selectProductsByCategoryId"  resultType="com.sl.po.Product">
            select * from products where categoryid=#{id} 
        </select>
        
</mapper>

啓用延遲加載和按需加載

Mybatis配置文件中經過兩個屬性lazyLoadingEnabled和aggressiveLazyLoading來控制延遲加載和按需加載。apache

lazyLoadingEnabled:是否啓用延遲加載,mybatis默認爲false,不啓用延遲加載。lazyLoadingEnabled屬性控制全局是否使用延遲加載,特殊關聯關係也能夠經過嵌套查詢中fetchType屬性單獨配置(fetchType屬性值lazy或者eager)。session

aggressiveLazyLoading:是否按需加載屬性,默認值false,lazyLoadingEnabled屬性啓用時只要加載對象,就會加載該對象的全部屬性;關閉該屬性則會按需加載,即便用到某關聯屬性時,實時執行嵌套查詢加載該屬性。mybatis

SqlMapConfig.xml中修改配置,註冊lazyLoadMapper.xmlapp

<settings>
    <!-- 啓用延遲加載特性,不配置默認關閉該特性-->
    <setting name="lazyLoadingEnabled" value="true"></setting>
    <!-- 按需加載: false:使用關聯屬性,及時加載;    true,加載對象,則加載全部屬性, -->
     <setting name="aggressiveLazyLoading" value="false"/>
    </settings>

<mappers>
        <!-- 註冊Mapper.xml文件 -->
        <mapper resource="mapper/lazyLoadMapper.xml"></mapper>        
</mappers>

運行測試

添加mapper接口ide

package com.sl.mapper;

import java.util.List;

import com.sl.po.Category;
import com.sl.po.Product;

public interface LazyLoadMapper {
    
    
    Category lazyLoadTest(int id);

    //嵌套查詢
    List<Product> selectProductsByCategoryId(int cId);
}
View Code

測試方法測試

package com.sl.test;

import java.io.IOException;
import java.io.InputStream;
import java.math.BigDecimal;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;

import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.Before;
import org.junit.Test;

import com.sl.mapper.LazyLoadMapper;
import com.sl.mapper.ProductMapper;
import com.sl.mapper.UnitMapper;
import com.sl.po.Category;
import com.sl.po.Product;
import com.sl.po.ProductDetailInfo;
import com.sl.po.ProductInfo;
import com.sl.po.ProductVo;
import com.sl.po.User;

import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

public class TestLazyLoadMapperClient {

    // 定義會話SqlSession
    SqlSession session = null;

    @Before
    public void init() throws IOException {
        // 定義mabatis全局配置文件
        String resource = "SqlMapConfig.xml";
        InputStream inputStream = Resources.getResourceAsStream(resource);
        SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
        SqlSessionFactory factory = builder.build(inputStream);
        // 根據sqlSessionFactory產生會話sqlsession
        session = factory.openSession();
    }

    // 延遲加載
    @Test
    public void testoneToManyTestCollectionSelect() {

        LazyLoadMapper mapper = session.getMapper(LazyLoadMapper.class);

        Category category = mapper.lazyLoadTest(1);

        //System.out.println(category);
        System.out.println(category.getName());

        if (category.getProductList().size() > 0) {
            for (Product pro : category.getProductList()) {
                System.out.println(pro);
            }
        }
        // 關閉會話
        session.close();
    }

}
View Code

運行程序查看sql執行記錄:fetch

當前配置:啓用延遲加載lazyLoadingEnabled=true和按需加載aggressiveLazyLoading=false

Step1: 執行Mapper方法lazyLoadTest,實際只執行了select * from category where id=#{id}

Step2: 執行System.out.println(category.getName()),加載屬性,因爲啓用按需加載aggressiveLazyLoading=false,name屬性此前已加載好,因此此處無數據庫交互

Step3: 執行category.getProductList().size(),加載屬性productList,按需加載須要執行延遲加載sql腳本select * from products where categoryid=#{id},與數據庫交互

 

將aggressiveLazyLoading屬性設爲爲true,即:

<setting name="aggressiveLazyLoading" value="false"/>

再一下執行過程:

此時的配置:啓用延遲加載lazyLoadingEnabled=true和關閉按需加載aggressiveLazyLoading=true(即加載對象則加載全部屬性)

Step1: 執行Mapper方法lazyLoadTest,實際只執行了select * from category where id=#{id}

Step2: 執行System.out.println(category.getName()),訪問name屬性,因爲啓用按需加載aggressiveLazyLoading=true,關閉按需加載,則加載category對象時加載該對象的全部屬性,執行延遲加載sql腳本select * from products where categoryid=#{id},與數據庫交互

Step3: 執行category.getProductList().size(),訪問productList屬性,該 性step2已加載好,此處無需數據庫交互

對比上下兩個step2能夠發現 aggressiveLazyLoading=true /false的區別。

相關文章
相關標籤/搜索