1.延迟加载是什么

延迟加载其实就是将数据加载时机推迟,比如推迟嵌套查询的执行时机。

2.为什么要进行延迟加载

在Mybatis中经常用到关联查询,但是并不是任何时候都需要立即返回关联查询结果。比如查询订单信息,并不一定需要及时返回订单对应的产品信息,查询商品分类信息并不一定要及时返回该类别下有哪些产品,这种情况一下需要一种机制,当需要查看时,再执行查询,返回需要的结果集,这种需求在Mybatis中可以使用延迟加载机制来实现。延迟加载可以实现先查询主表,按需实时做关联查询,返回关联表结果集,一定程度上提高了效率。

3.如何进行延迟加载

首先要开启Mybatis对延迟加载的支持
根据官方文档的描述,在mybatis的配置文件中开启延迟加载

 <settings>
        <!--开启二级缓存-->
        <setting name="cacheEnabled" value="true"/>
        <!--开启mybatis支持延迟加载-->
        <setting name="lazyLoadingEnabled" value="true"/>
        <!--false表示按需加载,true表示立即加载-->
        <setting name="aggressiveLazyLoading" value="false"/>
    </settings>

既然是管理查询,那么肯定在一个实体类中有其他实体类的映射

import java.io.Serializable;
import java.util.List;

/**
 * Created on 16:12  23/11/2019
 * Description:
 * user的实体类
 *
 * @author Weleness
 */

public class User implements Serializable {

    private Integer id;
    private String username;
    private String password;
    //一对多关系映射
    private List<Account> account;

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public List<Account> getAccount() {
        return account;
    }

    public void setAccount(List<Account> account) {
        this.account = account;
    }

    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", username='" + username + '\'' +
                ", password='" + password + '\'' +
                ", account=" + account +
                '}';
    }
}

要实现延迟加载,我们可以使用分段查询的方式,
分段查询又有两种方式,第一种是XML文档的配置方式
标注上属性fetchType=“lazy”

<?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="weleness.dao.IUserDao">
    <!--开启UserDao支持二级缓存-->
    <!--<cache/>-->
    <resultMap id="userMap" type="user">
       <!--property对应实体类中的映射签面    column对应需要传过去的参数-->
        <collection property="account" column="id" select="weleness.dao.IAccountDao.findAccountById"  ofType="weleness.pojo.Account" fetchType="lazy"/>
    </resultMap>
    <select id="findAll" useCache="true" resultMap="userMap">
        select * from user;
    </select>
    </mapper>

Account对应的方法配置

<?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="weleness.dao.IAccountDao">

    <select id="findAccountById" resultType="account">
        select  * from account where uid = #{id}
    </select>
</mapper>

测试代码,先不进行对account值的获取,先查找所有用户

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 weleness.dao.IUserDao;
import weleness.pojo.User;

import java.io.IOException;
import java.io.InputStream;
import java.util.List;

/**
 * Created on 16:14  23/11/2019
 * Description:
 *
 * @author Weleness
 */

public class UserTest {
    SqlSession sqlSession  = null;
    IUserDao dao = null;
    SqlSessionFactory factory = null;
    @Before
    public void init() throws IOException {
        //导入配置文件
        InputStream in = Resources.getResourceAsStream("SqlMapConfig.xml");
        //交给构建者构建工厂对象
       factory = new SqlSessionFactoryBuilder().build(in);
        sqlSession = factory.openSession();
        dao = sqlSession.getMapper(IUserDao.class);
    }

    @Test
    public void testFindAll(){
        List<User> all = dao.findAll();
       // for (User user : all) {
        //    System.out.println(user.getAccount());
       // }
        //List<Account> account = all.get(0).getAccount();
        //System.out.println(account);
        //String username = all.get(0).getUsername();
        //System.out.println(username);
    }
    }

控制台输出,可以看到并没进行account的sql操作
mybatis的延迟加载_分享
让我们来获取account的值

 @Test
    public void testFindAll(){
        List<User> all = dao.findAll();
        for (User user : all) {
            System.out.println(user.getAccount());
        }

可以看到,mybatis根据查询来的user的id,一条一条进行了id的查询
mybatis的延迟加载_分享_02
第二种是注解的方式配置
在要查询的方法上面加上@Results注解,里面有一个嵌套注解many,然后就和xml配置的方式差不多,当然,也要首先在配置文件中开启支持。

@Results(id = "userMap" , value = {@Result(property = "account",column = "id" , many = @Many(select = "weleness.dao.findAccountById",fetchType = FetchType.LAZY))})
@Select("select * from user")
    List<User> findAll();