MyBatis 性能优化之延迟加载

MyBatis 延迟加载

什么是延迟加载

延迟加载又叫懒加载,也叫按需加载,也就是说先加载主表信息,需要的时候,再去加载从表信息。代码中有查询语句,当执行到查询语句时,并不是马上去数据库中查询,而是根据设置的延迟策略将查询向后推迟

延迟加载的目的

减轻数据库服务器的压力,因为我们延迟加载只有在用到需要的数据才会执行查询操作。

启用延迟加载机制

Mybatis配置文件中通过两个属性 lazyLoadingEnabledaggressiveLazyLoading 来控制延迟加载和按需加载。

  • lazyLoadingEnabled:是否启用延迟加载,mybatis默认为false,不启用延迟加载。lazyLoadingEnabled属性控制全局是否使用延迟加载,特殊关联关系也可以通过嵌套查询中 fetchType 属性单独配置(fetchType属性值lazy或者eager)。

  • aggressiveLazyLoading:是否按需加载属性,默认值false。该属性为 true 时只要加载对象,就会加载该对象的所有属性;该属性为 false 则会按需加载,即使用到某关联属性时,实时执行嵌套查询加载该属性。

配置如下:

<settings>
    <!-- 启用延迟加载特性,不配置默认关闭该特性-->
    <setting name="lazyLoadingEnabled" value="true"></setting>
    <!-- 按需加载: false:使用关联属性,及时加载    true:加载对象,则加载所有属性 -->
    <setting name="aggressiveLazyLoading" value="false"/>
</settings>

测试延迟加载机制

  • 未开启延迟加载机制

在 mybastis-config.xml 中关闭延迟加载机制,如下:

<settings>
  <setting name="lazyLoadingEnabled" value="false" />
	<setting name="aggressiveLazyLoading" value="false"/>
  ... 
</settings>

在 MyBatisTest.java 中添加测试代码如下:

		@Test
    public void lazyLoadingTest() {
        RoleEntity roleEntity = gameMapper.selectRoleById(1);
        //System.out.println(roleEntity.getMoney());
    }

执行测试,结果如下:

2020-08-11 10:22:57,766 [main] [mapper.GameMapper.selectRoleById]-[DEBUG] ==>  Preparing: select * from tb_role where id=? 
2020-08-11 10:22:57,810 [main] [mapper.GameMapper.selectRoleById]-[DEBUG] ==> Parameters: 1(Integer)
2020-08-11 10:22:57,857 [main] [mapper.GameMapper.selectAccountById]-[DEBUG] ====>  Preparing: select * from tb_account where id=? 
2020-08-11 10:22:57,857 [main] [mapper.GameMapper.selectAccountById]-[DEBUG] ====> Parameters: 1(Integer)
2020-08-11 10:22:57,857 [main] [mapper.GameMapper.selectAccountById]-[DEBUG] <====      Total: 1
2020-08-11 10:22:57,857 [main] [mapper.GameMapper.selectRoleById]-[DEBUG] <==      Total: 1

从以上结果可以看出,打印了两条 SQL 语句,说明执行了关联查询。

  • 开启延迟加载机制
    <settings>
        <!-- 启用延迟加载特性,不配置默认关闭该特性-->
        <setting name="lazyLoadingEnabled" value="true"></setting>
        <!-- 按需加载: false:使用关联属性,及时加载    true:加载对象,则加载所有属性 -->
        <setting name="aggressiveLazyLoading" value="false"/>
    </settings>
    

    再次执行测试代码,结果如下:

    2020-08-11 10:26:31,779 [main] [mapper.GameMapper.selectRoleById]-[DEBUG] ==>  Preparing: select * from tb_role where id=? 
    2020-08-11 10:26:31,810 [main] [mapper.GameMapper.selectRoleById]-[DEBUG] ==> Parameters: 1(Integer)
    2020-08-11 10:26:31,982 [main] [mapper.GameMapper.selectRoleById]-[DEBUG] <==      Total: 1
    

    启动延迟加载后,只打印了一条 SQL 语句。

    现在我把测试代码修改一下,如下:

    		@Test
        public void lazyLoadingTest() {
            RoleEntity roleEntity = gameMapper.selectRoleById(1);
            System.out.println(roleEntity.getMoney());
        }
    

    将查询的主表的 money 属性值打印出来,执行测试结果如下:

    2020-08-11 10:27:47,982 [main] [mapper.GameMapper.selectRoleById]-[DEBUG] ==>  Preparing: select * from tb_role where id=? 
    2020-08-11 10:27:48,029 [main] [mapper.GameMapper.selectRoleById]-[DEBUG] ==> Parameters: 1(Integer)
    2020-08-11 10:27:48,185 [main] [mapper.GameMapper.selectRoleById]-[DEBUG] <==      Total: 1
    2000
    

    看到了吧,还是只有一条 SQL 查询语句,说明并未执行关联查询。

    现在我又把配置修改一下,

    <setting name="aggressiveLazyLoading" value="true"/>
    

    然后执行如下测试代码

    		@Test
        public void lazyLoadingTest() {
            RoleEntity roleEntity = gameMapper.selectRoleById(1);
            //System.out.println(roleEntity.getMoney());
        }
    

    测试结果如下:

    2020-08-11 10:41:00,826 [main] [mapper.GameMapper.selectRoleById]-[DEBUG] ==>  Preparing: select * from tb_role where id=? 
    2020-08-11 10:41:00,888 [main] [mapper.GameMapper.selectRoleById]-[DEBUG] ==> Parameters: 1(Integer)
    2020-08-11 10:41:01,029 [main] [mapper.GameMapper.selectRoleById]-[DEBUG] <==      Total: 1
    

    现在还是只打印了一条 SQL 查询语句,说明并未执行关联查询。

    修改一下测试代码如下:

    		@Test
        public void lazyLoadingTest() {
            RoleEntity roleEntity = gameMapper.selectRoleById(1);
            System.out.println(roleEntity.getMoney());
        }
    

    再次执行测试结果如下:

    2020-08-11 10:43:51,544 [main] [mapper.GameMapper.selectRoleById]-[DEBUG] ==>  Preparing: select * from tb_role where id=? 
    2020-08-11 10:43:51,576 [main] [mapper.GameMapper.selectRoleById]-[DEBUG] ==> Parameters: 1(Integer)
    2020-08-11 10:43:51,748 [main] [mapper.GameMapper.selectRoleById]-[DEBUG] <==      Total: 1
    2020-08-11 10:43:51,748 [main] [mapper.GameMapper.selectAccountById]-[DEBUG] ==>  Preparing: select * from tb_account where id=? 
    2020-08-11 10:43:51,748 [main] [mapper.GameMapper.selectAccountById]-[DEBUG] ==> Parameters: 1(Integer)
    2020-08-11 10:43:51,763 [main] [mapper.GameMapper.selectAccountById]-[DEBUG] <==      Total: 1
    2000
    

    现在打印了两条 SQL 查询语句,说明已经执行了关联查询。

总结

  • 什么是延迟加载
  • 延迟加载的目的是什么
  • 如何开启延迟加载
  • 按需加载和完全加载在区别是什么
posted @ 2021-09-28 18:52  嘛了对就念来过倒  阅读(267)  评论(0编辑  收藏  举报