MyBatis 性能优化之延迟加载
MyBatis 延迟加载
什么是延迟加载
延迟加载又叫懒加载,也叫按需加载,也就是说先加载主表信息,需要的时候,再去加载从表信息。代码中有查询语句,当执行到查询语句时,并不是马上去数据库中查询,而是根据设置的延迟策略将查询向后推迟
延迟加载的目的
减轻数据库服务器的压力,因为我们延迟加载只有在用到需要的数据才会执行查询操作。
启用延迟加载机制
Mybatis配置文件中通过两个属性 lazyLoadingEnabled 和 aggressiveLazyLoading 来控制延迟加载和按需加载。
-
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 查询语句,说明已经执行了关联查询。
总结
- 什么是延迟加载
- 延迟加载的目的是什么
- 如何开启延迟加载
- 按需加载和完全加载在区别是什么