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