【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 |
6.3 实体类
6.3.1 部门类
public class Dept { private Integer deptno; private String dname; private String loc; /** * 关系属性 */ private List 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 getEmpList() { return empList; } public void setEmpList(List 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 select();}public interface DeptMapper { /* * 根据部门编号查询部门信息 */ Dept selectById(Integer deptno);}
6.4.2 mapper文件
懒加载的前提是需要分离Sql,不再使用关联查询Sql。
比如我们要查询所有员工的信息,并关联查询部门信息;想要实现部门信息懒加载,那么查询员工信息是一条独立的Sql,根据部门编号查询部门信息也是一条独立的Sql,当查询员工信息的时候,如果需要用到部门信息,那么就调用根据部门编号查询部门信息的Sql。
根据部门编号查询部门信息:
select deptno,dname,loc from dept where deptno=#{deptno}
查询员工信息(单表查询),并通过上边的查询去关联部门信息:
association标签的属性:
select:执行延迟加载时关联数据查询的sql对应的statementId。
执行的关联查询语句在同一mapper文件中:直接填入statementId即可;
执行的关联查询语句在不同的mapper文件中:namespace.statementId;
column:在执行关系表信息查询时,与其关联的字段名称。
select empno,ename,job,mgr,hiredate,sal,comm,deptno from emp
6.4.3 测试
public class LazyLoadingTest { @Test public void testOneToOne() { SqlSession sqlSession = MybatisUtil.getSession(); EmpMapper empMapper = sqlSession.getMapper(EmpMapper.class); List 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 select();}public interface EmpMapper { /* * 根据部门编号查询对应的员工信息 */ List selectByDeptno(Integer deptno);}
6.5.2 mapper文件
根据部门编号查询员工信息:
select empno,ename,job,mgr,hiredate,sal,comm,deptno from emp where deptno=#{deptno}
查询部门信息(单表查询),并通过上边的查询去关联部门中的员工信息:
select deptno,dname,loc from dept
6.5.3 测试
@Testpublic void testOneToMany() { SqlSession sqlSession = MybatisUtil.getSession(); DeptMapper deptMapper = sqlSession.getMapper(DeptMapper.class); List list = deptMapper.select(); for (Dept dept : list) { System.out.println(dept.getDeptno() + "--" + dept.getDname() + "--" + dept.getLoc()); //查询关联信息 List empList = dept.getEmpList(); for (Emp emp : empList) { System.out.println("员工姓名:" + emp.getEname()); } } sqlSession.close();}