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.使用总结

  1. 开启全局懒加载
  2. 先单表查询,将查询结果放到resultMap,将关联的列对应的值通过column传递到另外的表对应的具体查询方法
  3. 当需要时再去执行对应的方法 懒加载
经验分享 程序员 微信小程序 职场和发展