Mybatis相关:懒加载(延迟加载)
1.什么是延迟加载?
延迟加载就是在需要用到数据时才进行加载,不需要用到数据时就不加载数据。延迟加载也称为懒加载。
好处:先从单表查询,需要时在从关联表去关联查询,大大提高数据库性能,因为查询单表比关联多张表查询速度要快得多。
坏处:因为只有当需要用到数据时,才会进行数据库查询,这样在大批量数据查询时,因为查询工作也要消耗时间,所以可能造成用户等待时间变长,造成用户体验下降。例如在查询学生信息时,要包括学生各科成绩。如果用懒加载,会变成,先查询出所有学生id,然后再拿这些id依次去数据库查询成绩,要与数据库发生很多次连接。但我明明可以用联表查询只和数据库打一次交道。
2.开启懒加载功能
在mybatis配置文件<settings>中开启全局懒加载,更常用
<!-- 开启全局懒加载--> <setting name="lazyLoadingEnabled" value="true"/> <setting name="aggressiveLazyLoading" value="false"/>
也可设置局部懒加载,仅针对当前sql语句,如
<resultMap id="studentWithScoreLazyMap" type="Student"> <id property="id" column="id"></id> <result property="name" column="name"></result> <result property="age" column="age"></result> <result property="sex" column="sex"></result> <result property="height" column="height"></result> <result property="sAddress" column="s_address"></result> <!--开启局部懒加载 fetchType="lazy"--> <collection property="scoreList" column="id" ofType="Score" select="com.qfedu.dao.IScoreDao.findAllScoreByStudentId" fetchType="lazy"> </collection>
fetchType="lazy" 默认情况就是懒加载 ,eager 立即加载 如果你开启了全局懒加载 又在此配置为 eager 则会覆盖全局的开启的懒加载功能,而是立即加载,即局部大于全局,类似就近原则
3.使用:一对多懒加载(以查询所有学生为例)
一对多懒加载与一对一懒加载类似,主要是一对多使用collection,而一对一使用association而已·,这里·已一对多举例
<!-- 一对多懒加载 1.查询所有的学生 select * from student_tb 2.根据学生的 id 查找到所有相关学生的成绩 列表 <collection property="scoreList" column="id" ofType="Score" select="com.qfedu.dao.ScoreDao.findAllScoreByStudentId"> property="scoreList" Student 类中的 成绩列表属性 ofType="Score" 集合中放置的类型 column="id" 学生id 数据表列名、 select="com.qfedu.dao.ScoreDao.findAllScoreByStudentId" 调用ScoreDao 中对应的方法并且 将 student表中列名 id 学生id对应的值给到这个方法 --> <resultMap id="studentWithScoreLazyMap" type="Student"> <id property="id" column="id"></id> <result property="name" column="name"></result> <result property="age" column="age"></result> <result property="sex" column="sex"></result> <result property="height" column="height"></result> <result property="sAddress" column="s_address"></result> <collection property="scoreList" column="id" ofType="Score" select="com.qfedu.dao.IScoreDao.findAllScoreByStudentId"> </collection> </resultMap> <select id="findAllStudentWithScoreLazy" resultMap="studentWithScoreLazyMap"> select * from student_tb </select>
<select id="findAllScoreByStudentId" resultType="Score"> select * from score_tb where studentid = #{id} </select>
这里与普通的一对多不同,<collection property="scoreList" column="id" ofType="Score" select="com.qfedu.dao.IScoreDao.findAllScoreByStudentId"></collection>中的column是必须写的,这是传递给.findAllScoreByStudentId接口中的参数,
select中是全限定类名+方法名,其余与普通的一对多映射相同。
4.测试
@Test //一对多懒加载 public void findAllStudentWithScoreLazyTest() { List<Student> studentList = iStudentDao.findAllStudentWithScoreLazy(); for (Student student : studentList) { //开启懒加载后不再查询score表,否则会继续查询 System.out.println("student-name:" + student.getName()); //需要这些数据时才会请求学生成绩 System.out.println("student-scoreList:" + student.getScoreList()); //一旦调用student的toString就会触发懒加载 //mybatis底层机制只要触发equals,clone,hashCode,toString就会懒加载 //可以在setting里面关闭功能 //System.out.println("student:" + student); } }
如果只访问学生基础信息而不访问成绩,此时是不会触发懒加载的,只会查询单表,如果访问了成绩,则会出发懒加载,查询学生id后,根据id再去获取成绩,所以耗时。
如果真要频繁获取学生成绩,还是联表查询比较快
5.注意:调用toString,equals,clone,hashCode默认触发懒加载的解决办法
在mybatis配置文件<settings>标签中配置如下
<!--解决 懒加载时 打印对象toString 触发 懒加载 lazyLoadTriggerMethods:指定哪个对象的方法触发一次延迟加载。默认值:equals,clone,hashCode,toString --> <setting name="lazyLoadTriggerMethods" value="false"/>
6.使用总结
- 开启全局懒加载
- 先单表查询,将查询结果放到resultMap,将关联的列对应的值通过column传递到另外的表对应的具体查询方法
- 当需要时再去执行对应的方法 懒加载