【Mybatis从入门到实战教程】第六章 Mybatis 延迟加载详解

六、Mybatis 延迟加载

6.1 什么是延迟加载

    需要查询关联信息时,使用MyBatis延迟加载特性可有效的减少数据库压力,首次查询只查询主要信息,关联信息等用户获取时再加载。
    
    懒加载针对级联使用的,懒加载的目的是减少内存的浪费和减轻系统负担。你可以理解为按需加载,当我调用到关联的数据时才与数据库交互否则不交互。
    
    resultMap可以实现高级映射(使用association、collection实现一对一和一对多映射),association、collection具备延迟加载功能。

6.2 打开延迟加载开关

    在MyBatis核心配置文件中配置:lazyLoadingEnabled、aggressiveLazyLoading。

设置项 描述 允许值 默认值
lazyLoadingEnabled 全局性设置懒加载。如果设为‘false’,则所有相关联的都会被初始化加载 true, false false
aggressiveLazyLoading 当设置为‘true’的时候,懒加载的对象可能被任何懒属性全部加载。否则,每个属性都按需加载 true, false true
<!-- 全局参数设置 -->
<settings>
    <!-- 开启延迟加载 -->
    <setting name="lazyLoadingEnabled" value="true"/>
    <setting name="aggressiveLazyLoading" value="false"/>
</settings>

6.3 实体类

6.3.1 部门类

public class Dept {

    private Integer deptno;
    private String dname;
    private String loc;
    /**
     * 关系属性
     */
    private List<Emp> empList;

    public Integer getDeptno() {
        return deptno;
    }

    public void setDeptno(Integer deptno) {
        this.deptno = deptno;
    }

    public String getDname() {
        return dname;
    }

    public void setDname(String dname) {
        this.dname = dname;
    }

    public String getLoc() {
        return loc;
    }

    public void setLoc(String loc) {
        this.loc = loc;
    }

    public List<Emp> getEmpList() {
        return empList;
    }

    public void setEmpList(List<Emp> empList) {
        this.empList = empList;
    }

    @Override
    public String toString() {
        return "Dept{" +
                "deptno=" + deptno +
                ", dname='" + dname + '\'' +
                ", loc='" + loc + '\'' +
                '}';
    }
}

6.3.2 员工类

public class Emp {

    private Integer empno;
    private String ename;
    private String job;
    private Integer mgr;
    private Date hiredate;
    private Double sal;
    private Double comm;
    private Integer deptno;
    /**
     * 关系属性
     */
    private Dept dept;

    public Integer getEmpno() {
        return empno;
    }

    public void setEmpno(Integer empno) {
        this.empno = empno;
    }

    public String getEname() {
        return ename;
    }

    public void setEname(String ename) {
        this.ename = ename;
    }

    public String getJob() {
        return job;
    }

    public void setJob(String job) {
        this.job = job;
    }

    public Integer getMgr() {
        return mgr;
    }

    public void setMgr(Integer mgr) {
        this.mgr = mgr;
    }

    public Date getHiredate() {
        return hiredate;
    }

    public void setHiredate(Date hiredate) {
        this.hiredate = hiredate;
    }

    public Double getSal() {
        return sal;
    }

    public void setSal(Double sal) {
        this.sal = sal;
    }

    public Double getComm() {
        return comm;
    }

    public void setComm(Double comm) {
        this.comm = comm;
    }

    public Integer getDeptno() {
        return deptno;
    }

    public void setDeptno(Integer deptno) {
        this.deptno = deptno;
    }

    public Dept getDept() {
        return dept;
    }

    public void setDept(Dept dept) {
        this.dept = dept;
    }

    @Override
    public String toString() {
        return "Emp{" +
                "empno=" + empno +
                ", ename='" + ename + '\'' +
                ", job='" + job + '\'' +
                ", mgr=" + mgr +
                ", hiredate=" + hiredate +
                ", sal=" + sal +
                ", comm=" + comm +
                ", deptno=" + deptno +
                '}';
    }
}

6.4 使用association实现延迟加载

    查询员工以及相关联的部门信息。

6.4.1 mapper接口

public interface EmpMapper {

    /*
     * 查询所有员工的信息,并关联查询部门信息
     */
    List<Emp> select();
}

public interface DeptMapper {

    /*
     * 根据部门编号查询部门信息
     */
    Dept selectById(Integer deptno);
}

6.4.2 mapper文件

    懒加载的前提是需要分离Sql,不再使用关联查询Sql。
    
    比如我们要查询所有员工的信息,并关联查询部门信息;想要实现部门信息懒加载,那么查询员工信息是一条独立的Sql,根据部门编号查询部门信息也是一条独立的Sql,当查询员工信息的时候,如果需要用到部门信息,那么就调用根据部门编号查询部门信息的Sql。

根据部门编号查询部门信息:

<?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.newcapec.mapper.DeptMapper">

    <select id="selectById" parameterType="java.lang.Integer" resultType="com.newcapec.entity.Dept">
        select deptno,dname,loc from dept where deptno=#{deptno}
    </select>
</mapper>

查询员工信息(单表查询),并通过上边的查询去关联部门信息:

    association标签的属性:
        select:执行延迟加载时关联数据查询的sql对应的statementId。
            执行的关联查询语句在同一mapper文件中:直接填入statementId即可;
            执行的关联查询语句在不同的mapper文件中:namespace.statementId;
        column:在执行关系表信息查询时,与其关联的字段名称。

<?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.newcapec.mapper.EmpMapper">

    <resultMap id="baseResultMap" type="com.newcapec.entity.Emp">
        <id column="empno" property="empno"/>
        <result column="ename" property="ename"/>
        <result column="job" property="job"/>
        <result column="mgr" property="mgr"/>
        <result column="hiredate" property="hiredate"/>
        <result column="sal" property="sal"/>
        <result column="comm" property="comm"/>
        <result column="deptno" property="deptno"/>
        <association property="dept" javaType="com.newcapec.entity.Dept"
                     select="com.newcapec.mapper.DeptMapper.selectById" column="deptno">
        </association>
    </resultMap>
    <select id="select" resultMap="baseResultMap">
        select empno,ename,job,mgr,hiredate,sal,comm,deptno from emp
    </select>
</mapper>

6.4.3 测试

public class LazyLoadingTest {

    @Test
    public void testOneToOne() {
        SqlSession sqlSession = MybatisUtil.getSession();
        EmpMapper empMapper = sqlSession.getMapper(EmpMapper.class);

        List<Emp> list = empMapper.select();
        for (Emp emp : list) {
            System.out.println(emp.getEmpno() + "--" + emp.getEname() + "--" + emp.getJob());
            System.out.println("----------");
            // 需要使用关联信息
            Dept dept = emp.getDept();
            if (dept != null) {
                System.out.println(dept.getDeptno() + "--" + dept.getDname() + "--" + dept.getLoc());
            }
            System.out.println("-----------------分割线----------------");
        }

        sqlSession.close();
    }
}

6.5 使用collection实现延迟加载

6.5.1 mapper接口

public interface DeptMapper {
    
    /*
     * 查询所有部门信息,并关联部门对应的员工信息
     */
    List<Dept> select();
}

public interface EmpMapper {

    /*
     * 根据部门编号查询对应的员工信息
     */
    List<Emp> selectByDeptno(Integer deptno);
}

6.5.2 mapper文件

根据部门编号查询员工信息:

<select id="selectByDeptno" parameterType="java.lang.Integer" resultType="com.newcapec.entity.Emp">
    select empno,ename,job,mgr,hiredate,sal,comm,deptno from emp where deptno=#{deptno}
</select>

查询部门信息(单表查询),并通过上边的查询去关联部门中的员工信息:

<resultMap id="baseResultMap" type="com.newcapec.entity.Dept">
    <id column="deptno" property="deptno"/>
    <result column="dname" property="dname"/>
    <result column="loc" property="loc"/>
    <!--关联信息描述-->
    <collection property="empList" ofType="com.newcapec.entity.Emp"
                select="com.newcapec.mapper.EmpMapper.selectByDeptno" column="deptno">
    </collection>
</resultMap>
<select id="select" resultMap="baseResultMap">
    select deptno,dname,loc from dept
</select>

6.5.3 测试

@Test
public void testOneToMany() {
    SqlSession sqlSession = MybatisUtil.getSession();

    DeptMapper deptMapper = sqlSession.getMapper(DeptMapper.class);
    List<Dept> list = deptMapper.select();
    for (Dept dept : list) {
        System.out.println(dept.getDeptno() + "--" + dept.getDname() + "--" + dept.getLoc());

        //查询关联信息
        List<Emp> empList = dept.getEmpList();
        for (Emp emp : empList) {
            System.out.println("员工姓名:" + emp.getEname());
        }
    }
    sqlSession.close();
}

猜你喜欢

转载自blog.csdn.net/ligonglanyuan/article/details/124397287