六、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();
}