什么是延迟加载

  • MyBatis中的延迟加载,也称为懒加载,是指在进行关联查询时,按照设置延迟规则推迟对关联对象的select查询。延迟加载可以有效的减少数据库压 力。
  • Mybatis的延迟加载,需要通过resultMap标签中的association和collection子标签才能演示成功。
  • Mybatis的延迟加载,也被称为是嵌套查询,对应的还有嵌套结果的概念,可以参考一对多关联的案例。
  • 注意:MyBatis的延迟加载只是对关联对象的查询有延迟设置, 对于主加载对象都是直接执行查询语句的。

关联查询分类

MyBatis根据对关联对象查询的select语句的执行时机,分为三种类型:直接加载、 侵入式加载与深度延迟加载

  • 直接加载: 执行完对主加载对象的select语句,马上执行对关联对象的select查询。
  • 侵入式延迟:执行对主加载对象的查询时,不会执行对关联对象的查询。但当要访问主加载对象的某个属性(该属性不是关联对象的属性)时,就会马 上执行关联对象的select查询。
  • 深度延迟: 执行对主加载对象的查询时,不会执行对关联对象的查询。访问主加载对象的详情时也不会执行关联对象的select查询。只有当真正访问关 联对象的详情时,才会执行对关联对象的select查询。

代码案例:

本篇基于一对多查询中的第二种分词查询,代码无须改动,只做配置修改

application.yml配置
侵入性延迟加载

  1. mybatis:
  2. configuration:
  3. # 全局启用或者禁用延迟加载 默认关闭
  4. lazy-loading-enabled: true
  5. # 侵入性延迟加载开关
  6. aggressive-lazy-loading: true

深度延迟加载

  1. mybatis:
  2. configuration:
  3. # 全局启用或者禁用延迟加载 默认关闭
  4. lazy-loading-enabled: true
  5. # 侵入性延迟加载开关
  6. aggressive-lazy-loading: false
  7. # 以下方法会触发延迟加载,不配置的时候默认为"equals", "clone", "hashCode", "toString"
  8. # lazy-load-trigger-methods: equals

编写单元测试

  1. @SpringBootTest
  2. class KkbStudyApplicationTests {
  3. @Autowired
  4. private UserMapper userMapper;
  5. @Test
  6. void test3() {
  7. UserExt query = userMapper.query2(2);
  8. System.err.println(query.getName());
  9. System.err.println(query);
  10. }
  11. }

控制台输出

  1. 2021-05-21 11:11:01.710 DEBUG 24008 --- [ main] c.e.kkbstudy.mapper.UserMapper.query2 : ==> Preparing: select `user`.id,`user`.name from `user`where `user`.id = ?
  2. 2021-05-21 11:11:01.741 DEBUG 24008 --- [ main] c.e.kkbstudy.mapper.UserMapper.query2 : ==> Parameters: 2(Integer)
  3. 2021-05-21 11:11:01.813 DEBUG 24008 --- [ main] c.e.kkbstudy.mapper.UserMapper.query2 : <== Total: 1
  4. 李四
  5. 2021-05-21 11:11:01.818 DEBUG 24008 --- [ main] c.e.k.mapper.OrderMapper.simpleQuery : ==> Preparing: select id,user_id,`desc` from `order` where user_id = ?
  6. 2021-05-21 11:11:01.819 DEBUG 24008 --- [ main] c.e.k.mapper.OrderMapper.simpleQuery : ==> Parameters: 2(Integer)
  7. 2021-05-21 11:11:01.820 DEBUG 24008 --- [ main] c.e.k.mapper.OrderMapper.simpleQuery : <== Total: 2
  8. [Order(id=1, userId=2, desc=第一笔订单), Order(id=2, userId=2, desc=第二笔订单)]

可以看到我们第一次去输出UserExt中的用户对象的时候并没有去触发查询order,直到我们去输出UserExt对象调用toString()方法的时候,才触发延迟加载,去查询了用户ID为2的订单对象。最终封装到了我们的UserExt对象中。

N+1问题

  • 深度延迟加载的使用会提升性能。
  • 如果延迟加载的表数据太多,此时会产生N+1问题,主信息加载一次算1次,而从信息是会根据主信息传递过来的条件,去查询从表多次。