延迟加载
延迟加载又称为懒加载或者按需加载,与之相反的概念为立即加载。从叫法上我喜欢称之为延迟加载,感觉更正式一些,从理解上称之为按需加载,更容易理解一些。所谓按需加载,就是在需要的时候才会去将其读取到内存,不需要时就不去加载它,从性能上来说这种方式更节约内存资源。
在Mybatis的association和collection中如果使用了select属性,就可以通过延迟加载来进行数据查询,此时主查询SQL中就不要先去进行关联查询,将关联查询放在select属性指向的从查询SQL中,如下图所示:
1 | <select id="queryHusbandInfoAndSonById" resultMap="queryHusbandInfoAndSonByIdMap"> |
为了能够使用延迟加载,还需要在mybatis的主配置文件中添加设置,因为默认情况下延迟加载是关闭的。需要注意的是,在主配置文件中是全局配置,所以会将所有的符合条件的查询都变为延迟加载:
1 | <!--延迟加载--> |
如果要进行局部设置,那就在XML中对应的association和collection标签中添加配置且优先级高于全局设置:
1 | fetchType="lazy" 延迟加载策略 // 需要手动开启 |
开启之后,就可以对上述的代码进行测试,这里使用logback在控制台打印日志信息,这样更能直观的判断SQL的执行流程,作为对比先使用默认的立即加载方式,然后再开启延迟加载。
附上单元测试代码:
1 |
|
立即加载下控制台的打印信息:
1 | [main] DEBUG c.w.m.H.queryHusbandInfoAndSonById - ==> Preparing: SELECT * FROM husband WHERE hid = ? |
从日志信息可以看出,一共执行了两次查询,虽然我仅仅是查询并没有使用到返回回来的数据
延迟加载下控制台的打印信息:
1 | [main] DEBUG c.w.m.H.queryHusbandInfoAndSonById - ==> Preparing: SELECT * FROM husband WHERE hid = ? |
从日志信息可以看出,只执行了一次查询,也就是主SQL查询执行了,collection中select对应的SQL并没有执行,因为我没有使用到从查询返回的数据
那么接下来,在延迟加载的方式下打印一下返回的数据,因为重写了toString(),会将所有查询的数据信息打印,也就是说会使用到从查询中的数据:
1 | [main] DEBUG c.w.m.H.queryHusbandInfoAndSonById - ==> Preparing: SELECT * FROM husband WHERE hid = ? |
从这次日志打印的结果来看,说明了只有在使用到从查询中返回的数据时,mybatis才会去执行从查询。
延迟加载的优缺点
优点在于: 当我们暂时只需要使用到实体类非关联属性时,只有在某种条件下才会使用关联属性,这种通过延迟加载可以先只进行主SQL查询,提高查询效率,也比较节省内存。
缺点在于:当数据量较大且频繁的使用关联属性时,延迟加载会增加查询的次数,消耗数据库性能