那一天,我爱上你,才知道,一切都变得那么不重要。 有幸遇见,Hello Java。
上一章简单介绍了MyBatis的一级缓存和二级缓存(十三),如果没有看过,请观看上一章。
MyBatis 延迟加载,是指在进行表的关联查询时,按照设置延迟规则推迟对关联对象的select查询。 如在查询 User 的信息时,如果没有用到Dept或者不想查询Dept,就不查询Dept 的信息,哪怕关联了Dept。 为了详细一些,老蝴蝶把以前的表信息拿出来。
User表:
Dept表:
IdCard 表:
对应的实体 类.
User.java
package com.yjl.pojo; /** @author:yuejl @date: 2019年6月15日 上午11:11:02 @Description Mybatis 使用的基本类 User */ public class User { /** * @param id id编号,自增 * @param name 姓名 * @param age 年龄 * @param sex 性别 * @param description 描述 */ private Integer id; private String name; private Integer age; private String sex; private String description; //引入部门的对象。 private IdCard idCard; private Dept dept; public User(){ } public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Integer getAge() { return age; } public void setAge(Integer age) { this.age = age; } public String getSex() { return sex; } public void setSex(String sex) { this.sex = sex; } public String getDescription() { return description; } public void setDescription(String description) { this.description = description; } public IdCard getIdCard() { return idCard; } public void setIdCard(IdCard idCard) { this.idCard = idCard; } public Dept getDept() { return dept; } public void setDept(Dept dept) { this.dept = dept; } @Override public String toString() { return "User [id=" + id + ", name=" + name + ", age=" + age + ", sex=" + sex + ", description=" + description + "]"; } }Dept.java
package com.yjl.pojo; import java.util.List; /** @author: yuejl @date: 2019年7月8日 上午10:15:08 @Description 数据库中一的一方 部门实体 */ public class Dept { /** * @param id 部门的编号 * @param name 部门的名称 * @param description 部门的描述 */ private Integer id; private String name; private String description; // 集合,用的是 List, 而不是Set private List<User> allUser; public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getDescription() { return description; } public void setDescription(String description) { this.description = description; } public List<User> getAllUser() { return allUser; } public void setAllUser(List<User> allUser) { this.allUser = allUser; } @Override public String toString() { return "Dept [id=" + id + ", name=" + name + ", description=" + description + "]"; } }IdCard.java
package com.yjl.pojo; /** @author: yuejl @date: 2019年7月5日 下午12:41:47 @Description 类的相关描述 */ public class IdCard { /** * @param uid 身份证唯一标识符 * @param idNum 身份证标识符 */ private Integer id; private String idNum; //引入员工的属性 private User userId; public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getIdNum() { return idNum; } public void setIdNum(String idNum) { this.idNum = idNum; } public User getUserId() { return userId; } public void setUserId(User userId) { this.userId = userId; } @Override public String toString() { return "IdCard [id=" + id + ", idNum=" + idNum + ", userId=" + userId + "]"; } }方法与前面讲关联关系时一样,故老蝴蝶在这里就不继续讲了。
UserMapper.java 接口:
public interface UserMapper { public User getByIdWithSelect(int id); public List<User> findUserByDeptId(@Param(value="deptId") int deptId); }DeptMapper.java 接口:
public interface DeptMapper { public Dept getById(int id); public Dept getAllInfoByIdWithSelect(int id); }IdCardMapper.java 接口:
public interface IdCardMapper { public IdCard findById(int id); }UserMapper.xml 语句:
<resultMap type="user" id="userResultMapWithSelect"> <id property="id" column="id"/> <result property="name" column="name"/> <result property="sex" column="sex"/> <result property="age" column="age"/> <result property="description" column="description"/> <association property="idCard" javaType="idCard" column="id" select="com.yjl.mapper.IdCardMapper.findByUserId"> </association> <association property="dept" javaType="dept" column="deptId" select="com.yjl.mapper.DeptMapper.getById" ></association> </resultMap> <select id="getByIdWithSelect" parameterType="int" resultMap="userResultMapWithSelect"> select * from user u where u.id=#{id} </select>DeptMapper.xml 语句
<resultMap type="dept" id="deptResultMap"> <id property="id" column="id"/> <result property="name" column="name"/> <result property="description" column="description"/> </resultMap> <!-- 嵌套结果 --> <select id="getById" parameterType="int" resultMap="deptResultMap"> select * from dept where id=#{id} </select>IdCardMapper.xml 语句:
<resultMap type="idCard" id="idCardResultMap"> <id property="id" column="id"/> <result property="idNum" column="idNum"/> </resultMap> <!-- 嵌套查询的sql, 没有对应的接口 --> <select id="findByUserId" parameterType="int" resultMap="idCardResultMap"> select * from idCard where uid=#{id} </select>进行了三次查询。 debug 一下,看查询的点在哪,是在getByIdWithSelect() 方法时, 还是在 user.getDept() ,user.getIdCard() 时。
执行了方法: 方法调用之后,就会去查询了。 这是全部查询的。
也是把 部门和身份证查询了出来。 当然,肯定也是在调用getByIdWithSelect() 方法时查询的。
设置延迟加载为 true, 默认为false. 这是延迟加载的总开关,必须开启。
将其设置为true.
<setting name="lazyLoadingEnabled" value="true"/>这个值,在3.4.1 版本之前,默认为true, 在3.4.1之后,就默认为false. 老蝴蝶的mybatis 版本为3.4.5 ,默认为false. 其中,设置时有些不同。 延迟加载时设置为false.
现设置为false
<setting name="aggressiveLazyLoading" value="true"/>发现依旧查询了 延迟加载并没有好使。 这并没有错。 查询资料, 将打印的 语句去除掉:
User user=userMapper.getByIdWithSelect(1); //System.out.println(user);测试运行 这个时候,就只查询一条了,延迟加载好用了。
但并不能去除掉 打印语句啊,不然怎么看呢。 原因还是在setting 设置时。
在setting 中有这么一条设置:
<setting name="lazyLoadTriggerMethods" value="equals,toString,clone,hashCode"/>即如果运行 equals,toString,clone,hasCode 方法时,将不延迟加载,而是立即加载。
将其中的toString 去除掉,再进行操作。
<setting name="lazyLoadTriggerMethods" value="equals,toString,clone,hashCode"/>继续测试 findByIdWithSelectF1Test() 方法, 加上那条打印语句。
也只查询了一个。 延迟加载成功。
这个方法,肯定查询三次,但要debug 测试一下,查询的点在哪,是一次性查出的,还是分别查询出的。
是用到的时候,才进行查询。
这个时候,测试运行 findByIdWithSelectF1Test()
发现,并没有延迟加载。 故需要将其字段设置为false 才可以。
有的时候,需要对同一个类 中的不同的属性分别进行设置 是否进行延迟加载, 如 查询员工时,把身份证信息查询出来,把部门延迟加载出来。 故在setting 的 lazyLoadingEnabled 设置总开头时,又设置了一个分开关。 fetchType , 默认为lazy, 延迟加载。 有两个值, lazy 延迟加载, eager 急切加载,即不延迟加载。
如分别设置 身份证为延迟加载, 部门为不延迟加载。
<association property="idCard" javaType="idCard" column="id" select="com.yjl.mapper.IdCardMapper.findByUserId" fetchType="lazy"> <association property="dept" javaType="dept" column="deptId" select="com.yjl.mapper.DeptMapper.getById" fetchType="eager"></association>这个时候,执行 findByIdWithSelectF1Test() 方法。(aggressiveLazyLoading 已经设置为false 了。)
查询了部门的信息,没有查询身份证信息, 身份证信息被延迟加载了。
接口上面写过了。
DeptMapper.xml sql语句:
<resultMap type="dept" id="deptCollectionResultMapWithSelect"> <id property="id" column="id"/> <result property="name" column="name"/> <result property="description" column="description"/> <!-- 用的是ofType的类型。 --> <collection property="allUser" ofType="user" column="id" select="com.yjl.mapper.UserMapper.findUserByDeptId"></collection> </resultMap> <select id="getAllInfoByIdWithSelect" parameterType="int" resultMap="deptCollectionResultMapWithSelect"> select * from dept where id=#{id} </select>UserMapper.xml 语句:
<resultMap type="user" id="userResultMap"> <id property="id" column="id"/> <result property="name" column="name"/> <result property="sex" column="sex"/> <result property="age" column="age"/> <result property="description" column="description"/> </resultMap> <select id="findUserByDeptId" parameterType="int" resultMap="userResultMap"> select * from user u where u.deptId=#{deptId} </select>测试方法:
@Test public void getAllInfoByIdWithSelectTest(){ SqlSession sqlSession=SqlSessionFactoryUtils.getSession(); DeptMapper deptMapper=sqlSession.getMapper(DeptMapper.class); Dept dept=deptMapper.getAllInfoByIdWithSelect(1); System.out.println(dept); }测试运行,发现只查询出了 部门的信息,并没有查询出员工的信息。
当使用员工集合时,才会查询。
@Test public void getAllInfoByIdWithSelectTest(){ SqlSession sqlSession=SqlSessionFactoryUtils.getSession(); DeptMapper deptMapper=sqlSession.getMapper(DeptMapper.class); Dept dept=deptMapper.getAllInfoByIdWithSelect(1); System.out.println(dept); List<User> allUser=dept.getAllUser(); allUser.forEach(n ->System.out.println(n)); }在调用 getAllUser() 方法时才会查询。
debug 运行的话:
getAllUser() 时进行查询: 输出: 当然,如果想将其改成 不延迟加载,而是立即查询,只需要 fetchType 改成eager 即可。
<!-- 用的是ofType的类型。 --> <collection property="allUser" ofType="user" column="id" select="com.yjl.mapper.UserMapper.findUserByDeptId" fetchType="eager"></collection>谢谢!!!
